Merged with tip.
[cacao.git] / src / vm / jit / replace.c
index 43b3d1d675e07ff5f624c862b12eb11a65d5c225..58f883c1ae997643f684efffb53abe806239c24e 100644 (file)
@@ -1,9 +1,7 @@
-/* vm/jit/replace.c - on-stack replacement of methods
+/* src/vm/jit/replace.c - on-stack replacement of methods
 
-   Copyright (C) 1996-2005, 2006 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
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Contact: cacao@cacaojvm.org
-
-   Authors: Edwin Steiner
-
-   $Id$
-
 */
 
 #include "config.h"
 #include "vm/types.h"
 
 #include <assert.h>
+#include <stdint.h>
 #include <stdlib.h>
 
 #include "arch.h"
+#include "md.h"
+
+#if defined(ENABLE_GC_CACAO)
+# include "mm/cacao-gc/gc.h"
+#endif
 
 #include "mm/memory.h"
+
+#include "threads/thread.h"
+
 #include "toolbox/logging.h"
-#include "vm/options.h"
+
 #include "vm/stringlocal.h"
+
 #include "vm/jit/abi.h"
-#include "vm/jit/jit.h"
-#include "vm/jit/replace.h"
-#include "vm/jit/stack.h"
 #include "vm/jit/asmpart.h"
 #include "vm/jit/disass.h"
-#include "vm/jit/show.h"
+#include "vm/jit/executionstate.h"
+#include "vm/jit/jit.h"
 #include "vm/jit/methodheader.h"
+#include "vm/jit/replace.h"
+#include "vm/jit/show.h"
+#include "vm/jit/stack.h"
 
-#include "native/include/java_lang_String.h"
+#include "vmcore/options.h"
+#include "vmcore/classcache.h"
+#if defined(ENABLE_RT_TIMING)
+#include "vmcore/rt-timing.h"
+#endif
 
 #define REPLACE_PATCH_DYNAMIC_CALL
 /*#define REPLACE_PATCH_ALL*/
 
+#if defined(ENABLE_VMLOG)
+#include <vmlog_cacao.h>
+#endif
+
+/*** architecture-dependent configuration *************************************/
+
+/* first unset the macros (default) */
+#undef REPLACE_RA_BETWEEN_FRAMES
+#undef REPLACE_RA_TOP_OF_FRAME
+#undef REPLACE_RA_LINKAGE_AREA
+#undef REPLACE_LEAFMETHODS_RA_REGISTER
+
+/* i386, x86_64 and m68k */
+#if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
+#define REPLACE_RA_BETWEEN_FRAMES
+/* alpha */
+#elif defined(__ALPHA__)
+#define REPLACE_RA_TOP_OF_FRAME
+#define REPLACE_LEAFMETHODS_RA_REGISTER
+/* powerpc */
+#elif defined(__POWERPC__)
+#define REPLACE_RA_LINKAGE_AREA
+#define REPLACE_LEAFMETHODS_RA_REGISTER
+/* s390 */
+#elif defined(__S390__)
+#define REPLACE_RA_TOP_OF_FRAME
+#endif
+
 
 /*** configuration of native stack slot size **********************************/
 
@@ -74,15 +109,14 @@ typedef u8 stackslot_t;
 
 /*** debugging ****************************************************************/
 
-/*#define REPLACE_VERBOSE*/
-
 #if !defined(NDEBUG)
-static void java_value_print(s4 type, u8 value);
-#endif /* !defined(NDEBUG) */
+static void java_value_print(s4 type, replace_val_t value);
+static void replace_stackframeinfo_println(stackframeinfo_t *sfi);
+#endif
 
-#if !defined(NDEBUG) && defined(REPLACE_VERBOSE)
-#define DOLOG(code) do{ if (1) { code; } } while(0)
-#define DOLOG_SHORT(code) do{ if (1) { code; } } while(0)
+#if !defined(NDEBUG)
+#define DOLOG(code)        do{ if (opt_TraceReplacement > 1) { code; } } while(0)
+#define DOLOG_SHORT(code)  do{ if (opt_TraceReplacement > 0) { code; } } while(0)
 #else
 #define DOLOG(code)
 #define DOLOG_SHORT(code)
@@ -213,17 +247,17 @@ static void replace_create_replacement_point(jitdata *jd,
                                continue;
 
                        ra->index = i;
-                       if (index < UNUSED) {
-                               ra->regoff = (UNUSED - index) - 1;
-                               ra->type = TYPE_RET;
-                               ra->flags = 0;
-                       }
-                       else {
+                       if (index >= 0) {
                                v = VAR(index);
                                ra->flags = v->flags & (INMEMORY);
                                ra->regoff = v->vv.regoff;
                                ra->type = v->type;
                        }
+                       else {
+                               ra->regoff = RETADDR_FROM_JAVALOCAL(index);
+                               ra->type = TYPE_RET;
+                               ra->flags = 0;
+                       }
                        ra++;
                }
        }
@@ -392,11 +426,6 @@ bool replace_create_replacement_points(jitdata *jd)
 
        m = code->m;
 
-       /* set codeinfo flags */
-
-       if (jd->isleafmethod)
-               CODE_SETFLAG_LEAFMETHOD(code);
-
        /* in instance methods, we may need a rplpoint at the method entry */
 
 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
@@ -441,6 +470,17 @@ bool replace_create_replacement_points(jitdata *jd)
 
                for (; iptr != iend; ++iptr) {
                        switch (iptr->opc) {
+#if defined(ENABLE_GC_CACAO)
+                               case ICMD_BUILTIN:
+                                       md = iptr->sx.s23.s3.bte->md;
+                                       count++;
+                                       COUNT_javalocals(javalocals, m, alloccount);
+                                       alloccount += iptr->s1.argcount;
+                                       if (iinfo)
+                                               alloccount -= iinfo->throughcount;
+                                       break;
+#endif
+
                                case ICMD_INVOKESTATIC:
                                case ICMD_INVOKESPECIAL:
                                case ICMD_INVOKEVIRTUAL:
@@ -580,6 +620,9 @@ bool replace_create_replacement_points(jitdata *jd)
                        replace_create_replacement_point(jd, iinfo, rp++,
                                        bptr->type, bptr->iinstr, &ra,
                                        bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
+
+                       if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
+                               rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
                }
 
                /* iterate over the instructions */
@@ -589,6 +632,19 @@ bool replace_create_replacement_points(jitdata *jd)
 
                for (; iptr != iend; ++iptr) {
                        switch (iptr->opc) {
+#if defined(ENABLE_GC_CACAO)
+                               case ICMD_BUILTIN:
+                                       md = iptr->sx.s23.s3.bte->md;
+
+                                       i = (iinfo) ? iinfo->throughcount : 0;
+                                       replace_create_replacement_point(jd, iinfo, rp++,
+                                                       RPLPOINT_TYPE_CALL, iptr, &ra,
+                                                       javalocals, iptr->sx.s23.s2.args,
+                                                       iptr->s1.argcount - i,
+                                                       md->paramcount);
+                                       break;
+#endif
+
                                case ICMD_INVOKESTATIC:
                                case ICMD_INVOKESPECIAL:
                                case ICMD_INVOKEVIRTUAL:
@@ -676,6 +732,9 @@ bool replace_create_replacement_points(jitdata *jd)
        code->globalcount   = 0;
        code->savedintcount = INT_SAV_CNT - rd->savintreguse;
        code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+       code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
+#endif
        code->memuse        = rd->memuse;
        code->stackframesize = jd->cd->stackframesize;
 
@@ -739,7 +798,6 @@ void replace_activate_replacement_points(codeinfo *code, bool mappable)
        rplpoint *rp;
        s4        i;
        s4        count;
-       s4        index;
        u1       *savedmcode;
 
        assert(code->savedmcode == NULL);
@@ -747,15 +805,12 @@ void replace_activate_replacement_points(codeinfo *code, bool mappable)
        /* count trappable replacement points */
 
        count = 0;
-       index = 0;
        i = code->rplpointcount;
        rp = code->rplpoints;
        for (; i--; rp++) {
                if (rp->flags & RPLPOINT_FLAG_NOTRAP)
                        continue;
 
-               index++;
-
                if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
                        continue;
 
@@ -779,8 +834,6 @@ void replace_activate_replacement_points(codeinfo *code, bool mappable)
                if (rp->flags & RPLPOINT_FLAG_NOTRAP)
                        continue;
 
-               index--;
-
                if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
                        continue;
 
@@ -789,9 +842,20 @@ void replace_activate_replacement_points(codeinfo *code, bool mappable)
 
                savedmcode -= REPLACEMENT_PATCH_SIZE;
 
-#if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
-               md_patch_replacement_point(code, index, rp, savedmcode);
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_DISASSEMBLER)
+               DOLOG( printf("\tinstruction before: ");
+                          disassinstr(rp->pc); fflush(stdout); );
+# endif
+
+               md_patch_replacement_point(rp->pc, savedmcode, false);
+
+# if defined(ENABLE_DISASSEMBLER)
+               DOLOG( printf("\tinstruction after : ");
+                          disassinstr(rp->pc); fflush(stdout); );
+# endif
 #endif
+
                rp->flags |= RPLPOINT_FLAG_ACTIVE;
        }
 
@@ -817,6 +881,23 @@ void replace_deactivate_replacement_points(codeinfo *code)
        s4        count;
        u1       *savedmcode;
 
+       if (code->savedmcode == NULL) {
+               /* disarm countdown points by patching the branches */
+
+               i = code->rplpointcount;
+               rp = code->rplpoints;
+               for (; i--; rp++) {
+                       if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
+                                       == RPLPOINT_FLAG_COUNTDOWN)
+                       {
+#if 0
+                               *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
+#endif
+                       }
+               }
+               return;
+       }
+
        assert(code->savedmcode != NULL);
        savedmcode = code->savedmcode;
 
@@ -834,8 +915,18 @@ void replace_deactivate_replacement_points(codeinfo *code)
                DOLOG( printf("deactivate replacement point:\n");
                           replace_replacement_point_println(rp, 1); fflush(stdout); );
 
-#if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
-               md_patch_replacement_point(code, -1, rp, savedmcode);
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_DISASSEMBLER)
+               DOLOG( printf("\tinstruction before: ");
+                          disassinstr(rp->pc); fflush(stdout); );
+# endif
+
+               md_patch_replacement_point(rp->pc, savedmcode, true);
+
+# if defined(ENABLE_DISASSEMBLER)
+               DOLOG( printf("\tinstruction before: ");
+                          disassinstr(rp->pc); fflush(stdout); );
+# endif
 #endif
 
                rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
@@ -863,7 +954,6 @@ void replace_deactivate_replacement_points(codeinfo *code)
    
    IN:
           es...............execution state
-          sp...............stack pointer of the execution state (XXX eliminate?)
           ra...............allocation
           javaval..........where to put the value
 
@@ -873,19 +963,18 @@ void replace_deactivate_replacement_points(codeinfo *code)
 *******************************************************************************/
 
 static void replace_read_value(executionstate_t *es,
-                                                          stackslot_t *sp,
                                                           rplalloc *ra,
-                                                          u8 *javaval)
+                                                          replace_val_t *javaval)
 {
        if (ra->flags & INMEMORY) {
                /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
 #ifdef HAS_4BYTE_STACKSLOT
                if (IS_2_WORD_TYPE(ra->type)) {
-                       *javaval = *(u8*)(sp + ra->regoff);
+                       javaval->l = *(u8*)(es->sp + ra->regoff);
                }
                else {
 #endif
-                       *javaval = sp[ra->regoff];
+                       javaval->p = *(ptrint*)(es->sp + ra->regoff);
 #ifdef HAS_4BYTE_STACKSLOT
                }
 #endif
@@ -893,10 +982,25 @@ static void replace_read_value(executionstate_t *es,
        else {
                /* allocated register */
                if (IS_FLT_DBL_TYPE(ra->type)) {
-                       *javaval = es->fltregs[ra->regoff];
+                       javaval->d = es->fltregs[ra->regoff];
+
+                       if (ra->type == TYPE_FLT)
+                               javaval->f = javaval->d;
+               }
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+               else if (IS_ADR_TYPE(ra->type)) {
+                       javaval->p = es->adrregs[ra->regoff];
                }
+#endif
                else {
-                       *javaval = es->intregs[ra->regoff];
+#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
+                       if (ra->type == TYPE_LNG) {
+                               javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
+                               javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
+                       }
+                       else
+#endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
+                               javaval->p = es->intregs[ra->regoff];
                }
        }
 }
@@ -908,53 +1012,99 @@ static void replace_read_value(executionstate_t *es,
    
    IN:
           es...............execution state
-          sp...............stack pointer of the execution state (XXX eliminate?)
           ra...............allocation
           *javaval.........the value
 
 *******************************************************************************/
 
 static void replace_write_value(executionstate_t *es,
-                                                           stackslot_t *sp,
                                                            rplalloc *ra,
-                                                           u8 *javaval)
+                                                           replace_val_t *javaval)
 {
        if (ra->flags & INMEMORY) {
                /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
 #ifdef HAS_4BYTE_STACKSLOT
                if (IS_2_WORD_TYPE(ra->type)) {
-                       *(u8*)(sp + ra->regoff) = *javaval;
+                       *(u8*)(es->sp + ra->regoff) = javaval->l;
                }
                else {
 #endif
-                       sp[ra->regoff] = *javaval;
+                       *(ptrint*)(es->sp + ra->regoff) = javaval->p;
 #ifdef HAS_4BYTE_STACKSLOT
                }
 #endif
        }
        else {
                /* allocated register */
-               if (IS_FLT_DBL_TYPE(ra->type)) {
-                       es->fltregs[ra->regoff] = *javaval;
-               }
-               else {
-                       es->intregs[ra->regoff] = *javaval;
+               switch (ra->type) {
+                       case TYPE_FLT:
+                               es->fltregs[ra->regoff] = (double) javaval->f;
+                               break;
+                       case TYPE_DBL:
+                               es->fltregs[ra->regoff] = javaval->d;
+                               break;
+#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
+                       case TYPE_LNG:
+                               es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
+                               es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
+                               break;
+#endif
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+                       case TYPE_ADR:
+                               es->adrregs[ra->regoff] = javaval->p;
+#endif
+                       default:
+                               es->intregs[ra->regoff] = javaval->p;
                }
        }
 }
 
 
-/* replace_read_executionstate *************************************************
+/* replace_new_sourceframe *****************************************************
 
-   Read the given executions state and translate it to a source frame.
+   Allocate a new source frame and insert it at the front of the frame list.
    
+   IN:
+          ss...............the source state
+
+   OUT:
+          ss->frames.......set to new frame (the new head of the frame list).
+
+   RETURN VALUE:
+       returns the new frame
+
+*******************************************************************************/
+
+static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
+{
+       sourceframe_t *frame;
+
+       frame = DNEW(sourceframe_t);
+       MZERO(frame, sourceframe_t, 1);
+
+       frame->down = ss->frames;
+       ss->frames = frame;
+
+       return frame;
+}
+
+
+/* replace_read_executionstate *************************************************
+
+   Read a source frame from the given executions state.
+   The new source frame is pushed to the front of the frame list of the
+   source state.
+
    IN:
        rp...............replacement point at which `es` was taken
           es...............execution state
-          ss...............where to put the source state
+          ss...............the source state to add the source frame to
+          topframe.........true, if the first (top-most) source frame on the
+                           stack is to be read
 
    OUT:
-       *ss..............the source state derived from the execution state
+       *ss..............the source state with the newly created source frame
+                           added
   
 *******************************************************************************/
 
@@ -968,6 +1118,7 @@ static s4 replace_normalize_type_map[] = {
 /* RPLPOINT_TYPE_BODY   |--> */ RPLPOINT_TYPE_STD
 };
 
+
 static void replace_read_executionstate(rplpoint *rp,
                                                                                executionstate_t *es,
                                                                                sourcestate_t *ss,
@@ -999,45 +1150,39 @@ static void replace_read_executionstate(rplpoint *rp,
 
        /* calculate base stack pointer */
 
-       basesp = sp + code_get_stack_frame_size(code);
+       basesp = sp + code->stackframesize;
 
        /* create the source frame */
 
-       frame = DNEW(sourceframe_t);
-       frame->down = ss->frames;
+       frame = replace_new_sourceframe(ss);
        frame->method = rp->method;
        frame->id = rp->id;
        assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
        frame->type = replace_normalize_type_map[rp->type];
-       frame->instance = 0;
-       frame->syncslotcount = 0;
-       frame->syncslots = NULL;
        frame->fromrp = rp;
        frame->fromcode = code;
-       frame->torp = NULL;
-       frame->tocode = NULL;
-
-       ss->frames = frame;
 
        /* read local variables */
 
        count = m->maxlocals;
        frame->javalocalcount = count;
-       frame->javalocals = DMNEW(u8, count);
+       frame->javalocals = DMNEW(replace_val_t, count);
        frame->javalocaltype = DMNEW(u1, count);
 
-#if !defined(NDEBUG)
        /* mark values as undefined */
        for (i=0; i<count; ++i) {
-               frame->javalocals[i] = (u8) 0x00dead0000dead00ULL;
+#if !defined(NDEBUG)
+               frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
+#endif
                frame->javalocaltype[i] = TYPE_VOID;
        }
 
        /* some entries in the intregs array are not meaningful */
        /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
-       es->intregs[REG_SP   ] = (u8) 0x11dead1111dead11ULL;
+#if !defined(NDEBUG)
+       es->intregs[REG_SP   ] = (ptrint) 0x11dead1111dead11ULL;
 #ifdef REG_PV
-       es->intregs[REG_PV   ] = (u8) 0x11dead1111dead11ULL;
+       es->intregs[REG_PV   ] = (ptrint) 0x11dead1111dead11ULL;
 #endif
 #endif /* !defined(NDEBUG) */
 
@@ -1050,9 +1195,9 @@ static void replace_read_executionstate(rplpoint *rp,
                assert(i < m->maxlocals);
                frame->javalocaltype[i] = ra->type;
                if (ra->type == TYPE_RET)
-                       frame->javalocals[i] = ra->regoff;
+                       frame->javalocals[i].i = ra->regoff;
                else
-                       replace_read_value(es, sp, ra, frame->javalocals + i);
+                       replace_read_value(es, ra, frame->javalocals + i);
                ra++;
                count--;
        }
@@ -1077,26 +1222,32 @@ static void replace_read_executionstate(rplpoint *rp,
                instra.regoff = md->params[0].regoff;
                if (md->params[0].inmemory) {
                        instra.flags = INMEMORY;
-                       instra.regoff += (1 + code->stackframesize);
+                       instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
                }
                else {
                        instra.flags = 0;
                }
-               replace_read_value(es, sp, &instra, &(frame->instance));
+               replace_read_value(es, &instra, &(frame->instance));
 #endif
        }
+#if defined(__I386__)
+       else if (!(rp->method->flags & ACC_STATIC)) {
+               /* On i386 we always pass the first argument on stack. */
+               frame->instance.a = *(java_object_t **)(basesp + 1);
+       } 
+#endif
 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
 
        /* read stack slots */
 
        frame->javastackdepth = count;
-       frame->javastack = DMNEW(u8, count);
+       frame->javastack = DMNEW(replace_val_t, count);
        frame->javastacktype = DMNEW(u1, count);
 
 #if !defined(NDEBUG)
        /* mark values as undefined */
        for (i=0; i<count; ++i) {
-               frame->javastack[i] = (u8) 0x00dead0000dead00ULL;
+               frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
                frame->javastacktype[i] = TYPE_VOID;
        }
 #endif /* !defined(NDEBUG) */
@@ -1109,7 +1260,8 @@ static void replace_read_executionstate(rplpoint *rp,
                assert(count);
 
                assert(ra->index == RPLALLOC_STACK);
-               frame->javastack[i] = sp[-1];
+               assert(ra->type == TYPE_ADR);
+               frame->javastack[i].p = sp[-1];
                frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
                count--;
                i++;
@@ -1119,7 +1271,8 @@ static void replace_read_executionstate(rplpoint *rp,
                assert(count);
 
                assert(ra->index == RPLALLOC_STACK);
-               frame->javastack[i] = es->intregs[REG_ITMP1];
+               assert(ra->type == TYPE_ADR);
+               frame->javastack[i].p = es->intregs[REG_ITMP1];
                frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
                count--;
                i++;
@@ -1129,7 +1282,7 @@ static void replace_read_executionstate(rplpoint *rp,
                assert(count);
 
                assert(ra->index == RPLALLOC_STACK);
-               frame->javastack[i] = 0;
+               frame->javastack[i].l = 0;
                frame->javastacktype[i] = TYPE_VOID;
                count--;
                i++;
@@ -1151,8 +1304,8 @@ static void replace_read_executionstate(rplpoint *rp,
                                assert(calleeframe->syncslots == NULL);
 
                                calleeframe->syncslotcount = 1;
-                               calleeframe->syncslots = DMNEW(u8, 1);
-                               replace_read_value(es,sp,ra,calleeframe->syncslots);
+                               calleeframe->syncslots = DMNEW(replace_val_t, 1);
+                               replace_read_value(es,ra,calleeframe->syncslots);
                        }
 
                        frame->javastackdepth--;
@@ -1168,9 +1321,9 @@ static void replace_read_executionstate(rplpoint *rp,
                }
                else {
                        if (ra->type == TYPE_RET)
-                               frame->javastack[i] = ra->regoff;
+                               frame->javastack[i].i = ra->regoff;
                        else
-                               replace_read_value(es,sp,ra,frame->javastack + i);
+                               replace_read_value(es,ra,frame->javastack + i);
                        frame->javastacktype[i] = ra->type;
                        i++;
                }
@@ -1180,13 +1333,16 @@ static void replace_read_executionstate(rplpoint *rp,
 
 /* replace_write_executionstate ************************************************
 
-   Translate the given source state into an execution state.
-   
+   Pop a source frame from the front of the frame list of the given source state
+   and write its values into the execution state.
+
    IN:
        rp...............replacement point for which execution state should be
-                           creates
-          es...............where to put the execution state
+                           created
+          es...............the execution state to modify
           ss...............the given source state
+          topframe.........true, if this is the last (top-most) source frame to be
+                           translated
 
    OUT:
        *es..............the execution state derived from the source state
@@ -1222,7 +1378,7 @@ static void replace_write_executionstate(rplpoint *rp,
 
        sp = (stackslot_t *) es->sp;
 
-       basesp = sp + code_get_stack_frame_size(code);
+       basesp = sp + code->stackframesize;
 
        /* in some cases the top stack slot is passed in REG_ITMP1 */
 
@@ -1243,7 +1399,7 @@ static void replace_write_executionstate(rplpoint *rp,
                        /* XXX assert that it matches this rplpoint */
                }
                else
-                       replace_write_value(es, sp, ra, frame->javalocals + i);
+                       replace_write_value(es, ra, frame->javalocals + i);
                count--;
                ra++;
        }
@@ -1260,7 +1416,7 @@ static void replace_write_executionstate(rplpoint *rp,
                assert(ra->index == RPLALLOC_STACK);
                assert(i < frame->javastackdepth);
                assert(frame->javastacktype[i] == TYPE_ADR);
-               sp[-1] = frame->javastack[i];
+               sp[-1] = frame->javastack[i].p;
                count--;
                i++;
                ra++;
@@ -1271,7 +1427,7 @@ static void replace_write_executionstate(rplpoint *rp,
                assert(ra->index == RPLALLOC_STACK);
                assert(i < frame->javastackdepth);
                assert(frame->javastacktype[i] == TYPE_ADR);
-               es->intregs[REG_ITMP1] = frame->javastack[i];
+               es->intregs[REG_ITMP1] = frame->javastack[i].p;
                count--;
                i++;
                ra++;
@@ -1300,7 +1456,7 @@ static void replace_write_executionstate(rplpoint *rp,
                                assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
                                assert(frame->down->syncslots != NULL);
 
-                               replace_write_value(es,sp,ra,frame->down->syncslots);
+                               replace_write_value(es,ra,frame->down->syncslots);
                        }
                        continue;
                }
@@ -1311,6 +1467,12 @@ static void replace_write_executionstate(rplpoint *rp,
 
                if (!topframe && ra->index == RPLALLOC_PARAM) {
                        /* skip it */
+                       /*
+                       ra->index = RPLALLOC_PARAM;
+                       replace_val_t v;
+                       v.l = 0;
+                       replace_write_value(es,ra,&v);
+                       */
                }
                else {
                        assert(i < frame->javastackdepth);
@@ -1319,7 +1481,7 @@ static void replace_write_executionstate(rplpoint *rp,
                                /* XXX assert that it matches this rplpoint */
                        }
                        else {
-                               replace_write_value(es,sp,ra,frame->javastack + i);
+                               replace_write_value(es,ra,frame->javastack + i);
                        }
                        i++;
                }
@@ -1331,75 +1493,73 @@ static void replace_write_executionstate(rplpoint *rp,
 }
 
 
-/* replace_pop_activation_record ***********************************************
+/* md_pop_stackframe ***********************************************************
+
+   Restore callee-saved registers (including the RA register),
+   set the stack pointer to the next stackframe,
+   set the PC to the return address of the popped frame.
 
-   Peel a stack frame from the execution state.
-   
    *** This function imitates the effects of the method epilog ***
    *** and returning from the method call.                     ***
 
    IN:
-          es...............execution state
-          frame............source frame, receives synchronization slots
+       es...............execution state
 
    OUT:
        *es..............the execution state after popping the stack frame
-  
+                        NOTE: es->code and es->pv are NOT updated.
+
 *******************************************************************************/
 
-u1* replace_pop_activation_record(executionstate_t *es,
-                                                                 sourceframe_t *frame)
+void md_pop_stackframe(executionstate_t *es)
 {
        u1 *ra;
-       u1 *pv;
+       s4 ra_align_off;
        s4 reg;
        s4 i;
-       s4 count;
-       codeinfo *code;
        stackslot_t *basesp;
        stackslot_t *sp;
 
        assert(es->code);
-       assert(frame);
-
-       /* read the return address */
-
-       ra = md_stacktrace_get_returnaddress(es->sp,
-                       SIZE_OF_STACKSLOT * es->code->stackframesize);
-
-       DOLOG( printf("return address: %p\n", (void*)ra); );
-
-       /* find the new codeinfo */
-
-       pv = md_codegen_get_pv_from_pc(ra);
-
-       DOLOG( printf("PV = %p\n", (void*) pv); );
 
-       if (pv == NULL)
-               return NULL;
+       /* alignment offset of RA */
 
-       code = *(codeinfo **)(pv + CodeinfoPointer);
+       ra_align_off = 0;
+#if defined(REPLACE_RA_BETWEEN_FRAMES)
+    if (es->code->stackframesize)
+               ra_align_off = SIZE_OF_STACKSLOT - SIZEOF_VOID_P;
+#endif
 
-       DOLOG( printf("CODE = %p\n", (void*) code); );
+       /* read the return address */
 
-       if (code == NULL)
-               return NULL;
+#if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
+       if (code_is_leafmethod(es->code))
+               ra = es->ra;
+       else
+#endif
+               ra = md_stacktrace_get_returnaddress(es->sp,
+                          SIZE_OF_STACKSLOT * es->code->stackframesize + ra_align_off);
 
        /* calculate the base of the stack frame */
 
        sp = (stackslot_t *) es->sp;
        basesp = sp + es->code->stackframesize;
 
-       /* read slots used for synchronization */
+       /* restore return address, if part of frame */
 
-       assert(frame->syncslotcount == 0);
-       assert(frame->syncslots == NULL);
-       count = code_get_sync_slot_count(es->code);
-       frame->syncslotcount = count;
-       frame->syncslots = DMNEW(u8, count);
-       for (i=0; i<count; ++i) {
-               frame->syncslots[i] = sp[es->code->memuse + i];
-       }
+#if defined(REPLACE_RA_TOP_OF_FRAME)
+#if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
+       if (!code_is_leafmethod(es->code))
+#endif
+               es->ra = (u1*) (ptrint) *--basesp;
+#endif /* REPLACE_RA_TOP_OF_FRAME */
+
+#if defined(REPLACE_RA_LINKAGE_AREA)
+#if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
+       if (!code_is_leafmethod(es->code))
+#endif
+               es->ra = (u1*) (ptrint) basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
+#endif /* REPLACE_RA_LINKAGE_AREA */
 
        /* restore saved int registers */
 
@@ -1418,181 +1578,484 @@ u1* replace_pop_activation_record(executionstate_t *es,
                while (nregdescfloat[--reg] != REG_SAV)
                        ;
                basesp -= STACK_SLOTS_PER_FLOAT;
-               es->fltregs[reg] = *(u8*)basesp;
+               es->fltregs[reg] = *(double*)basesp;
        }
 
-       /* Set the new pc. Subtract one so we do not hit the replacement point */
-       /* of the instruction following the call, if there is one.             */
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+       /* restore saved adr registers */
 
-       es->pc = ra - 1;
+       reg = ADR_REG_CNT;
+       for (i=0; i<es->code->savedadrcount; ++i) {
+               while (nregdescadr[--reg] != REG_SAV)
+                       ;
+               es->adrregs[reg] = *--basesp;
+       }
+#endif
 
        /* adjust the stackpointer */
 
        es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
-       es->sp += SIZE_OF_STACKSLOT; /* skip return address */
 
-       es->pv = pv;
-       es->code = code;
+#if defined(REPLACE_RA_BETWEEN_FRAMES)
+       es->sp += ra_align_off + SIZEOF_VOID_P; /* skip return address */
+#endif
+
+       /* set the program counter to the return address */
+
+       es->pc = ra;
+
+       /* in debugging mode clobber non-saved registers */
 
 #if !defined(NDEBUG)
        /* for debugging */
        for (i=0; i<INT_REG_CNT; ++i)
                if (nregdescint[i] != REG_SAV)
-                       es->intregs[i] = 0x33dead3333dead33ULL;
+                       es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
        for (i=0; i<FLT_REG_CNT; ++i)
                if (nregdescfloat[i] != REG_SAV)
-                       es->fltregs[i] = 0x33dead3333dead33ULL;
+                       *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
+# if defined(HAS_ADDRESS_REGISTER_FILE)
+       for (i=0; i<ADR_REG_CNT; ++i)
+               if (nregdescadr[i] != REG_SAV)
+                       es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
+# endif
 #endif /* !defined(NDEBUG) */
-
-       return ra;
 }
 
 
-/* replace_patch_method_pointer ************************************************
+/* md_push_stackframe **********************************************************
 
-   Patch a method pointer (may be in code, data segment, vftbl, or interface
-   table).
+   Save the given return address, build the new stackframe,
+   and store callee-saved registers.
+
+   *** This function imitates the effects of a call and the ***
+   *** method prolog of the callee.                         ***
 
    IN:
-          mpp..............address of the method pointer to patch
-          entrypoint.......the new entrypoint of the method
-          kind.............kind of call to patch, used only for debugging
+       es...............execution state
+       calleecode.......the code we are "calling"
+       ra...............the return address to save
+
+   OUT:
+       *es..............the execution state after pushing the stack frame
+                        NOTE: es->pc, es->code, and es->pv are NOT updated.
 
 *******************************************************************************/
 
-static void replace_patch_method_pointer(methodptr *mpp,
-                                                                                methodptr entrypoint,
-                                                                                const char *kind)
+void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra)
 {
-#if !defined(NDEBUG)
-       codeinfo       *oldcode;
-       codeinfo       *newcode;
-#endif
-
-       DOLOG( printf("patch method pointer from: %p to %p\n",
-                                 (void*) *mpp, (void*)entrypoint); );
+       s4           reg;
+       s4           i;
+       stackslot_t *basesp;
+       stackslot_t *sp;
 
-#if !defined(NDEBUG)
-       oldcode = *(codeinfo **)((u1*)(*mpp) + CodeinfoPointer);
-       newcode = *(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer);
+       assert(es);
+       assert(calleecode);
 
-       DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
-                                method_println(oldcode->m);
-                                printf("\t      with      %p ", (void*) newcode);
-                                method_println(newcode->m); );
+       /* write the return address */
 
-       assert(oldcode->m == newcode->m);
-#endif
+#if defined(REPLACE_RA_BETWEEN_FRAMES)
+       es->sp -= SIZEOF_VOID_P;
+       *((void **)es->sp) = (void *) ra;
+       if (calleecode->stackframesize)
+               es->sp -= (SIZE_OF_STACKSLOT - SIZEOF_VOID_P);
+#endif /* REPLACE_RA_BETWEEN_FRAMES */
 
-       /* write the new entrypoint */
+       es->ra = (u1*) (ptrint) ra;
 
-       *mpp = (methodptr) entrypoint;
-}
+       /* build the stackframe */
 
+       DOLOG( printf("building stackframe of %d words at %p\n",
+                                 calleecode->stackframesize, (void*)es->sp); );
 
-/* replace_patch_future_calls **************************************************
+       sp = (stackslot_t *) es->sp;
+       basesp = sp;
 
-   Analyse a call site and depending on the kind of call patch the call, the
-   virtual function table, or the interface table.
+       sp -= calleecode->stackframesize;
+       es->sp = (u1*) sp;
 
-   IN:
-          ra...............return address pointing after the call site
-          callerframe......source frame of the caller
-          calleeframe......source frame of the callee, must have been mapped
+       /* in debug mode, invalidate stack frame first */
 
-*******************************************************************************/
+       /* XXX may not invalidate linkage area used by native code! */
 
-void replace_patch_future_calls(u1 *ra,
-                                                               sourceframe_t *callerframe,
-                                                               sourceframe_t *calleeframe)
-{
-       u1                *patchpos;
-       methodptr          entrypoint;
-       methodptr          oldentrypoint;
-       methodptr         *mpp;
-       methodptr         *mppend;
-       bool               atentry;
-       stackframeinfo     sfi;
-       codeinfo          *calleecode;
-       methodinfo        *calleem;
-       java_objectheader *obj;
-       struct _vftbl     *vftbl;
-       s4                 i;
+#if !defined(NDEBUG) && 0
+       for (i=0; i< (basesp - sp) && i < 1; ++i) {
+               sp[i] = 0xdeaddeadU;
+       }
+#endif
 
-       assert(ra);
-       assert(callerframe->down == calleeframe);
+#if defined(__I386__)
+       /* Stackslot 0 may contain the object instance for vftbl patching.
+          Destroy it, so there's no undefined value used. */
+       if ((basesp - sp) > 0) {
+               sp[0] = 0;
+       }
+#endif
 
-       /* get the new codeinfo and the method that shall be entered */
+       /* save the return address register */
 
-       calleecode = calleeframe->tocode;
-       assert(calleecode);
+#if defined(REPLACE_RA_TOP_OF_FRAME)
+#if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
+       if (!code_is_leafmethod(calleecode))
+#endif
+               *--basesp = (ptrint) ra;
+#endif /* REPLACE_RA_TOP_OF_FRAME */
 
-       calleem = calleeframe->method;
-       assert(calleem == calleecode->m);
+#if defined(REPLACE_RA_LINKAGE_AREA)
+#if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
+       if (!code_is_leafmethod(calleecode))
+#endif
+               basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
+#endif /* REPLACE_RA_LINKAGE_AREA */
 
-       entrypoint = (methodptr) calleecode->entrypoint;
+       /* save int registers */
 
-       /* check if we are at an method entry rplpoint at the innermost frame */
+       reg = INT_REG_CNT;
+       for (i=0; i<calleecode->savedintcount; ++i) {
+               while (nregdescint[--reg] != REG_SAV)
+                       ;
+               *--basesp = es->intregs[reg];
 
-       atentry = (calleeframe->down == NULL)
-                       && !(calleem->flags & ACC_STATIC)
-                       && (calleeframe->fromrp->id == 0); /* XXX */
+               /* XXX may not clobber saved regs used by native code! */
+#if !defined(NDEBUG) && 0
+               es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
+#endif
+       }
 
-       /* get the position to patch, in case it was a statically bound call   */
+       /* save flt registers */
 
-       sfi.pv = callerframe->fromcode->entrypoint;
-       patchpos = md_get_method_patch_address(ra, &sfi, NULL);
+       /* XXX align? */
+       reg = FLT_REG_CNT;
+       for (i=0; i<calleecode->savedfltcount; ++i) {
+               while (nregdescfloat[--reg] != REG_SAV)
+                       ;
+               basesp -= STACK_SLOTS_PER_FLOAT;
+               *(double*)basesp = es->fltregs[reg];
+
+               /* XXX may not clobber saved regs used by native code! */
+#if !defined(NDEBUG) && 0
+               *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
+#endif
+       }
+
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+       /* save adr registers */
+
+       reg = ADR_REG_CNT;
+       for (i=0; i<calleecode->savedadrcount; ++i) {
+               while (nregdescadr[--reg] != REG_SAV)
+                       ;
+               *--basesp = es->adrregs[reg];
+
+               /* XXX may not clobber saved regs used by native code! */
+#if !defined(NDEBUG) && 0
+               es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
+#endif
+       }
+#endif
+}
+
+
+/* replace_pop_activation_record ***********************************************
+
+   Peel a stack frame from the execution state.
+
+   *** This function imitates the effects of the method epilog ***
+   *** and returning from the method call.                     ***
+
+   IN:
+       es...............execution state
+       frame............source frame, receives synchronization slots
+
+   OUT:
+       *es..............the execution state after popping the stack frame
+
+   RETURN VALUE:
+       the return address of the poped activation record
+
+*******************************************************************************/
+
+u1* replace_pop_activation_record(executionstate_t *es,
+                                                                 sourceframe_t *frame)
+{
+       u1 *ra;
+       u1 *pv;
+       s4 i;
+       s4 count;
+       codeinfo *code;
+       stackslot_t *sp;
+
+       assert(es->code);
+       assert(frame);
+
+       /* calculate the base of the stack frame */
+
+       sp = (stackslot_t *) es->sp;
+       assert(frame->syncslotcount == 0);
+       assert(frame->syncslots == NULL);
+       count = code_get_sync_slot_count(es->code);
+       frame->syncslotcount = count;
+       frame->syncslots = DMNEW(replace_val_t, count);
+       for (i=0; i<count; ++i) {
+               frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX md_ function */
+       }
+
+       /* pop the stackframe */
+
+       md_pop_stackframe(es);
+
+       ra = es->pc;
+
+       DOLOG( printf("RA = %p\n", (void*)ra); );
+
+       /* Subtract one from the PC so we do not hit the replacement point */
+       /* of the instruction following the call, if there is one.         */
+
+       es->pc--;
+
+       /* find the new codeinfo */
+
+       pv = md_codegen_get_pv_from_pc(ra);
+       DOLOG( printf("PV = %p\n", (void*) pv); );
+
+       code = code_get_codeinfo_for_pv(pv);
+       DOLOG( printf("CODE = %p\n", (void*) code); );
+
+       /* return NULL if we reached native code */
+
+       es->pv = pv;
+       es->code = code;
+
+       return (code) ? ra : NULL;
+}
+
+
+/* replace_patch_method_pointer ************************************************
+
+   Patch a method pointer (may be in code, data segment, vftbl, or interface
+   table).
+
+   IN:
+          mpp..............address of the method pointer to patch
+          entrypoint.......the new entrypoint of the method
+          kind.............kind of call to patch, used only for debugging
+
+*******************************************************************************/
+
+static void replace_patch_method_pointer(methodptr *mpp,
+                                                                                methodptr entrypoint,
+                                                                                const char *kind)
+{
+#if !defined(NDEBUG)
+       codeinfo       *oldcode;
+       codeinfo       *newcode;
+#endif
+
+       DOLOG( printf("patch method pointer from: %p to %p\n",
+                                 (void*) *mpp, (void*)entrypoint); );
+
+#if !defined(NDEBUG)
+       oldcode = code_get_codeinfo_for_pv(*mpp);
+       newcode = code_get_codeinfo_for_pv(entrypoint);
+
+       DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
+                                method_println(oldcode->m);
+                                printf("\t      with      %p ", (void*) newcode);
+                                method_println(newcode->m); );
+
+       assert(oldcode->m == newcode->m);
+#endif
+
+       /* write the new entrypoint */
+
+       *mpp = (methodptr) entrypoint;
+}
+
+
+/* replace_patch_class *********************************************************
+
+   Patch a method in the given class.
+
+   IN:
+          vftbl............vftbl of the class
+          m................the method to patch
+          oldentrypoint....the old entrypoint to replace
+          entrypoint.......the new entrypoint
+
+*******************************************************************************/
+
+void replace_patch_class(vftbl_t *vftbl,
+                                                methodinfo *m,
+                                                u1 *oldentrypoint,
+                                                u1 *entrypoint)
+{
+       s4                 i;
+       methodptr         *mpp;
+       methodptr         *mppend;
+
+       /* patch the vftbl of the class */
+
+       replace_patch_method_pointer(vftbl->table + m->vftblindex,
+                                                                entrypoint,
+                                                                "virtual  ");
+
+       /* patch the interface tables */
+
+       assert(oldentrypoint);
+
+       for (i=0; i < vftbl->interfacetablelength; ++i) {
+               mpp = vftbl->interfacetable[-i];
+               mppend = mpp + vftbl->interfacevftbllength[i];
+               for (; mpp != mppend; ++mpp)
+                       if (*mpp == oldentrypoint) {
+                               replace_patch_method_pointer(mpp, entrypoint, "interface");
+                       }
+       }
+}
+
+
+/* replace_patch_class_hierarchy ***********************************************
+
+   Patch a method in all loaded classes.
+
+   IN:
+          m................the method to patch
+          oldentrypoint....the old entrypoint to replace
+          entrypoint.......the new entrypoint
+
+*******************************************************************************/
+
+struct replace_patch_data_t {
+       methodinfo *m;
+       u1         *oldentrypoint;
+       u1         *entrypoint;
+};
+
+void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
+{
+       vftbl_t *vftbl = c->vftbl;
+
+       if (vftbl != NULL
+               && vftbl->vftbllength > pd->m->vftblindex
+               && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
+               && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
+       {
+               replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
+       }
+}
+
+void replace_patch_class_hierarchy(methodinfo *m,
+                                                                  u1 *oldentrypoint,
+                                                                  u1 *entrypoint)
+{
+       struct replace_patch_data_t pd;
+
+       pd.m = m;
+       pd.oldentrypoint = oldentrypoint;
+       pd.entrypoint = entrypoint;
+
+       DOLOG_SHORT( printf("patching class hierarchy: ");
+                            method_println(m); );
+
+       classcache_foreach_loaded_class(
+                       (classcache_foreach_functionptr_t) &replace_patch_callback,
+                       (void*) &pd);
+}
+
+
+/* replace_patch_future_calls **************************************************
+
+   Analyse a call site and depending on the kind of call patch the call, the
+   virtual function table, or the interface table.
+
+   IN:
+          ra...............return address pointing after the call site
+          callerframe......source frame of the caller
+          calleeframe......source frame of the callee, must have been mapped
+
+*******************************************************************************/
+
+void replace_patch_future_calls(u1 *ra,
+                                                               sourceframe_t *callerframe,
+                                                               sourceframe_t *calleeframe)
+{
+       u1            *patchpos;
+       methodptr      entrypoint;
+       methodptr      oldentrypoint;
+       bool           atentry;
+       void          *pv;
+       codeinfo      *calleecode;
+       methodinfo    *calleem;
+       java_object_t *obj;
+       vftbl_t       *vftbl;
+
+       assert(ra);
+       assert(callerframe->down == calleeframe);
+
+       /* get the new codeinfo and the method that shall be entered */
+
+       calleecode = calleeframe->tocode;
+       assert(calleecode);
+
+       calleem = calleeframe->method;
+       assert(calleem == calleecode->m);
+
+       entrypoint = (methodptr) calleecode->entrypoint;
+
+       /* check if we are at an method entry rplpoint at the innermost frame */
+
+       atentry = (calleeframe->down == NULL)
+                       && !(calleem->flags & ACC_STATIC)
+                       && (calleeframe->fromrp->id == 0); /* XXX */
+
+       /* get the position to patch, in case it was a statically bound call   */
+
+       pv = callerframe->fromcode->entrypoint;
+       patchpos = md_jit_method_patch_address(pv, ra, NULL);
 
        if (patchpos == NULL) {
                /* the call was dispatched dynamically */
 
                /* we can only patch such calls if we are at the entry point */
 
+#if !defined(__I386__)
+               /* On i386 we always know the instance argument. */
                if (!atentry)
                        return;
+#endif
 
                assert((calleem->flags & ACC_STATIC) == 0);
 
+               oldentrypoint = calleeframe->fromcode->entrypoint;
+
                /* we need to know the instance */
 
-               if (!calleeframe->instance) {
+               if (!calleeframe->instance.a) {
                        DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
+                       replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
                        return;
                }
 
                /* get the vftbl */
 
-               obj = (java_objectheader *) (ptrint) calleeframe->instance;
+               obj = calleeframe->instance.a;
                vftbl = obj->vftbl;
 
-               assert(vftbl->class->vftbl == vftbl);
-
-               DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
-
-               /* patch the vftbl of the class */
-
-               replace_patch_method_pointer(vftbl->table + calleem->vftblindex,
-                                                                        entrypoint,
-                                                                        "virtual");
+               assert(vftbl->clazz->vftbl == vftbl);
 
-               /* patch the interface tables */
+               DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->clazz); );
 
-               oldentrypoint = calleeframe->fromcode->entrypoint;
-               assert(oldentrypoint);
-
-               for (i=0; i < vftbl->interfacetablelength; ++i) {
-                       mpp = vftbl->interfacetable[-i];
-                       mppend = mpp + vftbl->interfacevftbllength[i];
-                       for (; mpp != mppend; ++mpp)
-                               if (*mpp == oldentrypoint) {
-                                       replace_patch_method_pointer(mpp, entrypoint, "interface");
-                               }
-               }
+               replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
        }
        else {
                /* the call was statically bound */
 
-               replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static");
+#if defined(__I386__)
+               /* It happens that there is a patcher trap. (pm) */
+               if (*(u2 *)(patchpos - 1) == 0x0b0f) {
+               } else
+#endif
+               replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static   ");
        }
 }
 
@@ -1607,7 +2070,8 @@ void replace_patch_future_calls(u1 *ra,
    IN:
           es...............execution state
           rpcall...........the replacement point at the call site
-          callerframe......source frame of the caller
+          callerframe......source frame of the caller, or NULL for creating the
+                           first frame
           calleeframe......source frame of the callee, must have been mapped
 
    OUT:
@@ -1620,111 +2084,60 @@ void replace_push_activation_record(executionstate_t *es,
                                                                        sourceframe_t *callerframe,
                                                                        sourceframe_t *calleeframe)
 {
-       s4           reg;
        s4           i;
        s4           count;
-       stackslot_t *basesp;
        stackslot_t *sp;
        u1          *ra;
        codeinfo    *calleecode;
 
        assert(es);
-       assert(rpcall && rpcall->type == RPLPOINT_TYPE_CALL);
-       assert(callerframe);
+       assert(!rpcall || callerframe);
+    assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
+       assert(!rpcall || rpcall == callerframe->torp);
        assert(calleeframe);
-       assert(calleeframe == callerframe->down);
+       assert(!callerframe || calleeframe == callerframe->down);
 
        /* the compilation unit we are entering */
 
        calleecode = calleeframe->tocode;
        assert(calleecode);
 
-       /* write the return address */
-
-       es->sp -= SIZE_OF_STACKSLOT;
+       /* calculate the return address */
 
-       ra = rpcall->pc + rpcall->callsize;
+       if (rpcall)
+               ra = rpcall->pc + rpcall->callsize;
+       else
+               ra = es->pc + 1 /* XXX this is ugly */;
 
-       DOLOG( printf("writing return address %p to %p\n",
-                               (void*) ra, (void*) es->sp); );
+       /* push the stackframe */
 
-       *((stackslot_t *)es->sp) = (stackslot_t) ra;
+       md_push_stackframe(es, calleecode, ra);
 
-       /* we move into a new code unit */
+       /* we move into a new code unit, set code, PC, PV */
 
        es->code = calleecode;
-
-       /* set the new pc XXX not needed */
-
-       es->pc = calleecode->entrypoint;
-
-       /* build the stackframe */
-
-       DOLOG( printf("building stackframe of %d words at %p\n",
-                                 calleecode->stackframesize, (void*)es->sp); );
-
-       sp = (stackslot_t *) es->sp;
-       basesp = sp;
-
-       sp -= calleecode->stackframesize;
-       es->sp = (u1*) sp;
-
-       /* in debug mode, invalidate stack frame first */
-
-#if !defined(NDEBUG)
-       for (i=0; i<(basesp - sp); ++i) {
-               sp[i] = 0xdeaddeadU;
-       }
-#endif
-
-       /* save int registers */
-
-       reg = INT_REG_CNT;
-       for (i=0; i<calleecode->savedintcount; ++i) {
-               while (nregdescint[--reg] != REG_SAV)
-                       ;
-               *--basesp = es->intregs[reg];
-
-#if !defined(NDEBUG)
-               es->intregs[reg] = 0x44dead4444dead44ULL;
-#endif
-       }
-
-       /* save flt registers */
-
-       /* XXX align? */
-       reg = FLT_REG_CNT;
-       for (i=0; i<calleecode->savedfltcount; ++i) {
-               while (nregdescfloat[--reg] != REG_SAV)
-                       ;
-               basesp -= STACK_SLOTS_PER_FLOAT;
-               *(u8*)basesp = es->fltregs[reg];
-
-#if !defined(NDEBUG)
-               es->fltregs[reg] = 0x44dead4444dead44ULL;
-#endif
-       }
+       es->pc = calleecode->entrypoint; /* XXX not needed? */
+       es->pv = calleecode->entrypoint;
 
        /* write slots used for synchronization */
 
+       sp = (stackslot_t *) es->sp;
        count = code_get_sync_slot_count(calleecode);
        assert(count == calleeframe->syncslotcount);
        for (i=0; i<count; ++i) {
-               sp[calleecode->memuse + i] = calleeframe->syncslots[i];
+               sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
        }
 
-       /* set the PV */
-
-       es->pv = calleecode->entrypoint;
-
        /* redirect future invocations */
 
+       if (callerframe && rpcall) {
 #if defined(REPLACE_PATCH_ALL)
-       if (rpcall->type == callerframe->fromrp->type)
+               if (rpcall->type == callerframe->fromrp->type)
 #else
-       if (rpcall == callerframe->fromrp)
+               if (rpcall == callerframe->fromrp)
 #endif
-               replace_patch_future_calls(ra, callerframe, calleeframe);
+                       replace_patch_future_calls(ra, callerframe, calleeframe);
+       }
 }
 
 
@@ -1754,6 +2167,7 @@ rplpoint * replace_find_replacement_point(codeinfo *code,
        s4        stacki;
        rplalloc *ra;
 
+       assert(code);
        assert(frame);
 
        DOLOG( printf("searching replacement point for:\n");
@@ -1780,13 +2194,13 @@ rplpoint * replace_find_replacement_point(codeinfo *code,
                                if (ra->type == TYPE_RET) {
                                        if (ra->index == RPLALLOC_STACK) {
                                                assert(stacki < frame->javastackdepth);
-                                               if (frame->javastack[stacki] != ra->regoff)
+                                               if (frame->javastack[stacki].i != ra->regoff)
                                                        goto no_match;
                                                stacki++;
                                        }
                                        else {
                                                assert(ra->index >= 0 && ra->index < frame->javalocalcount);
-                                               if (frame->javalocals[ra->index] != ra->regoff)
+                                               if (frame->javalocals[ra->index].i != ra->regoff)
                                                        goto no_match;
                                        }
                                }
@@ -1815,7 +2229,9 @@ no_match:
 
 /* replace_find_replacement_point_for_pc ***************************************
 
-   Find the nearest replacement point at or before the given PC.
+   Find the nearest replacement point at or before the given PC. The
+   given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
+   the replacement point to be found.
 
    IN:
        code.............compilation unit the PC is in
@@ -1827,22 +2243,247 @@ no_match:
 
 *******************************************************************************/
 
-rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
+rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc, unsigned desired_flags)
 {
        rplpoint *found;
        rplpoint *rp;
        s4        i;
 
+       DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
+                  method_println(code->m); );
+
        found = NULL;
 
        rp = code->rplpoints;
-       for (i=0; i<code->rplpointcount; ++i, ++rp)
-               if (rp->pc <= pc)
-                       found = rp;
+       for (i=0; i<code->rplpointcount; ++i, ++rp) {
+               DOLOG( replace_replacement_point_println(rp, 2); );
+               if (rp->pc <= pc && rp->pc + rp->callsize >= pc) {
+                       if (desired_flags) {
+                               if (rp->flags & desired_flags) {
+                                       found = rp;
+                               }
+                       } else {
+                               found = rp;
+                       }
+               }
+       }
 
        return found;
 }
 
+/* replace_pop_native_frame ****************************************************
+
+   Unroll a native frame in the execution state and create a source frame
+   for it.
+
+   IN:
+          es...............current execution state
+          ss...............the current source state
+          sfi..............stackframeinfo for the native frame
+
+   OUT:
+       es...............execution state after unrolling the native frame
+          ss...............gets the added native source frame
+
+*******************************************************************************/
+
+static void replace_pop_native_frame(executionstate_t *es,
+                                                                        sourcestate_t *ss,
+                                                                        stackframeinfo_t *sfi)
+{
+       sourceframe_t *frame;
+       codeinfo      *code;
+       s4             i,j;
+
+       assert(sfi);
+
+       frame = replace_new_sourceframe(ss);
+
+       frame->sfi = sfi;
+
+       /* remember pc and size of native frame */
+
+       frame->nativepc = es->pc;
+       frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
+       assert(frame->nativeframesize >= 0);
+
+       /* remember values of saved registers */
+
+       j = 0;
+       for (i=0; i<INT_REG_CNT; ++i) {
+               if (nregdescint[i] == REG_SAV)
+                       frame->nativesavint[j++] = es->intregs[i];
+       }
+
+       j = 0;
+       for (i=0; i<FLT_REG_CNT; ++i) {
+               if (nregdescfloat[i] == REG_SAV)
+                       frame->nativesavflt[j++] = es->fltregs[i];
+       }
+
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+       j = 0;
+       for (i=0; i<ADR_REG_CNT; ++i) {
+               if (nregdescadr[i] == REG_SAV)
+                       frame->nativesavadr[j++] = es->adrregs[i];
+       }
+#endif
+
+       /* restore saved registers */
+
+#if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
+       j = 0;
+       for (i=0; i<INT_REG_CNT; ++i) {
+               if (nregdescint[i] == REG_SAV)
+                       es->intregs[i] = sfi->intregs[j++];
+       }
+#else
+       /* XXX we don't have them, yet, in the sfi, so clear them */
+
+       for (i=0; i<INT_REG_CNT; ++i) {
+               if (nregdescint[i] == REG_SAV)
+                       es->intregs[i] = 0;
+       }
+#endif
+
+       /* XXX we don't have float registers in the sfi, so clear them */
+
+       for (i=0; i<FLT_REG_CNT; ++i) {
+               if (nregdescfloat[i] == REG_SAV)
+                       es->fltregs[i] = 0.0;
+       }
+
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+# if defined(ENABLE_GC_CACAO)
+       j = 0;
+       for (i=0; i<ADR_REG_CNT; ++i) {
+               if (nregdescadr[i] == REG_SAV)
+                       es->adrregs[i] = sfi->adrregs[j++];
+       }
+# else
+       for (i=0; i<ADR_REG_CNT; ++i) {
+               if (nregdescadr[i] == REG_SAV)
+                       es->adrregs[i] = 0;
+       }
+# endif
+#endif
+
+       /* restore codeinfo of the native stub */
+
+       code = code_get_codeinfo_for_pv(sfi->pv);
+
+       /* restore sp, pv, pc and codeinfo of the parent method */
+
+       /* XXX michi: use this instead:
+       es->sp = sfi->sp + code->stackframesize; */
+       es->sp   = sfi->sp + (*(s4 *) (sfi->pv + FrameSize));
+#if defined(REPLACE_RA_BETWEEN_FRAMES)
+       es->sp  += SIZE_OF_STACKSLOT; /* skip return address */
+#endif
+       es->pv   = md_codegen_get_pv_from_pc(sfi->ra);
+       es->pc   = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
+       es->code = code_get_codeinfo_for_pv(es->pv);
+}
+
+
+/* replace_push_native_frame ***************************************************
+
+   Rebuild a native frame onto the execution state and remove its source frame.
+
+   Note: The native frame is "rebuild" by setting fields like PC and stack
+         pointer in the execution state accordingly. Values in the
+                stackframeinfo may be modified, but the actual stack frame of the
+                native code is not touched.
+
+   IN:
+          es...............current execution state
+          ss...............the current source state
+
+   OUT:
+       es...............execution state after re-rolling the native frame
+          ss...............the native source frame is removed
+
+*******************************************************************************/
+
+static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
+{
+       sourceframe_t *frame;
+       s4             i,j;
+
+       assert(es);
+       assert(ss);
+
+       DOLOG( printf("pushing native frame\n"); );
+
+       /* remove the frame from the source state */
+
+       frame = ss->frames;
+       assert(frame);
+       assert(REPLACE_IS_NATIVE_FRAME(frame));
+
+       ss->frames = frame->down;
+
+       /* skip sp for the native stub */
+
+       es->sp -= (*(s4 *) (frame->sfi->pv + FrameSize));
+#if defined(REPLACE_RA_BETWEEN_FRAMES)
+       es->sp -= SIZE_OF_STACKSLOT; /* skip return address */
+#endif
+
+       /* assert that the native frame has not moved */
+
+       assert(es->sp == frame->sfi->sp);
+
+       /* update saved registers in the stackframeinfo */
+
+#if defined(ENABLE_GC_CACAO)
+       j = 0;
+# if !defined(HAS_ADDRESS_REGISTER_FILE)
+       for (i=0; i<INT_REG_CNT; ++i) {
+               if (nregdescint[i] == REG_SAV)
+                       frame->sfi->intregs[j++] = es->intregs[i];
+       }
+# else
+       for (i=0; i<ADR_REG_CNT; ++i) {
+               if (nregdescadr[i] == REG_SAV)
+                       frame->sfi->adrregs[j++] = es->adrregs[i];
+       }
+# endif
+
+       /* XXX leave float registers untouched here */
+#endif
+
+       /* restore saved registers */
+
+       j = 0;
+       for (i=0; i<INT_REG_CNT; ++i) {
+               if (nregdescint[i] == REG_SAV)
+                       es->intregs[i] = frame->nativesavint[j++];
+       }
+
+       j = 0;
+       for (i=0; i<FLT_REG_CNT; ++i) {
+               if (nregdescfloat[i] == REG_SAV)
+                       es->fltregs[i] = frame->nativesavflt[j++];
+       }
+
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+       j = 0;
+       for (i=0; i<ADR_REG_CNT; ++i) {
+               if (nregdescadr[i] == REG_SAV)
+                       es->adrregs[i] = frame->nativesavadr[j++];
+       }
+#endif
+
+       /* skip the native frame on the machine stack */
+
+       es->sp -= frame->nativeframesize;
+
+       /* set the pc the next frame must return to */
+
+       es->pc = frame->nativepc;
+}
+
 
 /* replace_recover_source_state ************************************************
 
@@ -1850,7 +2491,8 @@ rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
    state.
 
    IN:
-       rp...............replacement point that has been reached
+       rp...............replacement point that has been reached, if any
+          sfi..............stackframeinfo, if called from native code
           es...............execution state at the replacement point rp
 
    RETURN VALUE:
@@ -1859,10 +2501,12 @@ rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
 *******************************************************************************/
 
 sourcestate_t *replace_recover_source_state(rplpoint *rp,
+                                                                                       stackframeinfo_t *sfi,
                                                                                    executionstate_t *es)
 {
        sourcestate_t *ss;
        u1            *ra;
+       bool           locked;
 #if defined(REPLACE_STATISTICS)
        s4             depth;
 #endif
@@ -1875,8 +2519,26 @@ sourcestate_t *replace_recover_source_state(rplpoint *rp,
        /* each iteration of the loop recovers one source frame */
 
        depth = 0;
+       locked = false;
+
+       while (rp || sfi) {
 
-       while (true) {
+               DOLOG( executionstate_println(es); );
+
+               /* if we are not at a replacement point, it is a native frame */
+
+               if (rp == NULL) {
+                       DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
+
+                       locked = true;
+                       replace_pop_native_frame(es, ss, sfi);
+                       sfi = sfi->prev;
+
+                       if (es->code == NULL)
+                               continue;
+
+                       goto after_machine_frame;
+               }
 
                /* read the values for this source frame from the execution state */
 
@@ -1886,12 +2548,23 @@ sourcestate_t *replace_recover_source_state(rplpoint *rp,
 
                replace_read_executionstate(rp, es, ss, ss->frames == NULL);
 
+#if defined(ENABLE_VMLOG)
+               vmlog_cacao_unrol_method(ss->frames->method);
+#endif
+
 #if defined(REPLACE_STATISTICS)
                REPLACE_COUNT(stat_frames);
                depth++;
                replace_statistics_source_frame(ss->frames);
 #endif
 
+               /* in locked areas (below native frames), identity map the frame */
+
+               if (locked) {
+                       ss->frames->torp = ss->frames->fromrp;
+                       ss->frames->tocode = ss->frames->fromcode;
+               }
+
                /* unroll to the next (outer) frame */
 
                if (rp->parent) {
@@ -1905,17 +2578,26 @@ sourcestate_t *replace_recover_source_state(rplpoint *rp,
                        REPLACE_COUNT(stat_unroll_inline);
                }
                else {
-                       /* this frame had been called at machine-level */
+                       /* this frame had been called at machine-level. pop it. */
 
                        DOLOG( printf("UNWIND\n"); );
 
                        ra = replace_pop_activation_record(es, ss->frames);
                        if (ra == NULL) {
-                               DOLOG( printf("BREAKING\n"); );
-                               break;
+                               DOLOG( printf("REACHED NATIVE CODE\n"); );
+
+                               rp = NULL;
+
+#if !defined(ENABLE_GC_CACAO)
+                               break; /* XXX remove to activate native frames */
+#endif
+                               continue;
                        }
 
-                       rp = replace_find_replacement_point_for_pc(es->code, es->pc);
+                       /* find the replacement point at the call site */
+
+after_machine_frame:
+                       rp = replace_find_replacement_point_for_pc(es->code, es->pc, 0);
 
                        if (rp == NULL)
                                vm_abort("could not find replacement point while unrolling call");
@@ -1941,7 +2623,6 @@ sourcestate_t *replace_recover_source_state(rplpoint *rp,
    frame, it is (re)compiled.
 
    IN:
-       firstcode........XXX temporary hack, will be removed
        ss...............the source state
 
    OUT:
@@ -1954,7 +2635,7 @@ sourcestate_t *replace_recover_source_state(rplpoint *rp,
 
 *******************************************************************************/
 
-static bool replace_map_source_state(codeinfo *firstcode, sourcestate_t *ss)
+static bool replace_map_source_state(sourcestate_t *ss)
 {
        sourceframe_t *frame;
        codeinfo      *code;
@@ -1965,41 +2646,64 @@ static bool replace_map_source_state(codeinfo *firstcode, sourcestate_t *ss)
 #endif
 
        parent = NULL;
+       code = NULL;
 
        /* iterate over the source frames from outermost to innermost */
 
-       code = firstcode; /* XXX should get code for first frame */
-
-       frame = ss->frames;
-       while (true) {
+       for (frame = ss->frames; frame != NULL; frame = frame->down) {
 
-               /* map this frame */
+               /* XXX skip native frames */
 
-               rp = replace_find_replacement_point(code, frame, parent);
+               if (REPLACE_IS_NATIVE_FRAME(frame)) {
+                       parent = NULL;
+                       continue;
+               }
 
-               frame->tocode = code;
-               frame->torp = rp;
+               /* map frames which are not already mapped */
 
-               /* go down one frame */
+               if (frame->tocode) {
+                       code = frame->tocode;
+                       rp = frame->torp;
+                       assert(rp);
+               }
+               else {
+                       assert(frame->torp == NULL);
 
-               frame = frame->down;
-               if (frame == NULL)
-                       break;
+                       if (parent == NULL) {
+                               /* find code for this frame */
 
-               if (rp->type == RPLPOINT_TYPE_CALL) {
 #if defined(REPLACE_STATISTICS)
-                       oldcode = frame->method->code;
+                               oldcode = frame->method->code;
 #endif
-                       code = jit_get_current_code(frame->method);
+                               /* request optimization of hot methods and their callers */
 
-                       if (code == NULL)
-                               return false; /* exception */
+                               if (frame->method->hitcountdown < 0
+                                       || (frame->down && frame->down->method->hitcountdown < 0))
+                                       jit_request_optimization(frame->method);
 
-                       REPLACE_COUNT_IF(stat_recompile, code != oldcode);
+                               code = jit_get_current_code(frame->method);
 
+                               if (code == NULL)
+                                       return false; /* exception */
+
+                               REPLACE_COUNT_IF(stat_recompile, code != oldcode);
+                       }
+
+                       assert(code);
+
+                       /* map this frame */
+
+                       rp = replace_find_replacement_point(code, frame, parent);
+
+                       frame->tocode = code;
+                       frame->torp = rp;
+               }
+
+               if (rp->type == RPLPOINT_TYPE_CALL) {
                        parent = NULL;
                }
                else {
+                       /* inlining */
                        parent = rp;
                }
        }
@@ -2008,7 +2712,53 @@ static bool replace_map_source_state(codeinfo *firstcode, sourcestate_t *ss)
 }
 
 
-/* replace_build_execution_state_intern ****************************************
+/* replace_map_source_state_identity *******************************************
+
+   Map each source frame in the given source state to the same replacement
+   point and compilation unit it was derived from. This is mainly used for
+   garbage collection.
+
+   IN:
+       ss...............the source state
+
+   OUT:
+       ss...............the source state, modified: The `torp` and `tocode`
+                           fields of each source frame are set.
+
+*******************************************************************************/
+
+#if defined(ENABLE_GC_CACAO)
+static void replace_map_source_state_identity(sourcestate_t *ss)
+{
+       sourceframe_t *frame;
+
+       /* iterate over the source frames from outermost to innermost */
+
+       for (frame = ss->frames; frame != NULL; frame = frame->down) {
+
+               /* skip native frames */
+
+               if (REPLACE_IS_NATIVE_FRAME(frame)) {
+                       continue;
+               }
+
+               /* map frames using the identity mapping */
+
+               if (frame->tocode) {
+                       assert(frame->tocode == frame->fromcode);
+                       assert(frame->torp   == frame->fromrp);
+               } else {
+                       assert(frame->tocode == NULL);
+                       assert(frame->torp   == NULL);
+                       frame->tocode = frame->fromcode;
+                       frame->torp   = frame->fromrp;
+               }
+       }
+}
+#endif
+
+
+/* replace_build_execution_state ***********************************************
 
    Build an execution state for the given (mapped) source state.
 
@@ -2026,237 +2776,344 @@ static bool replace_map_source_state(codeinfo *firstcode, sourcestate_t *ss)
 
 *******************************************************************************/
 
-static void replace_build_execution_state_intern(sourcestate_t *ss,
-                                                                                                executionstate_t *es)
+static void replace_build_execution_state(sourcestate_t *ss,
+                                                                                 executionstate_t *es)
 {
        rplpoint      *rp;
        sourceframe_t *prevframe;
+       rplpoint      *parent;
+
+       parent = NULL;
+       prevframe = NULL;
+       rp = NULL;
 
-       while (true) {
+       while (ss->frames) {
 
-               rp = ss->frames->torp;
+               if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
+                       prevframe = ss->frames;
+                       replace_push_native_frame(es, ss);
+                       parent = NULL;
+                       rp = NULL;
+                       continue;
+               }
+
+               if (parent == NULL) {
+                       /* create a machine-level stack frame */
+
+                       DOLOG( printf("pushing activation record for:\n");
+                                  if (rp) replace_replacement_point_println(rp, 1);
+                                  else printf("\tfirst frame\n"); );
 
+                       replace_push_activation_record(es, rp, prevframe, ss->frames);
+
+                       DOLOG( executionstate_println(es); );
+               }
+
+               rp = ss->frames->torp;
                assert(rp);
-               assert(es->code == ss->frames->tocode);
 
                DOLOG( printf("creating execution state for%s:\n",
                                (ss->frames->down == NULL) ? " TOPFRAME" : "");
                           replace_replacement_point_println(ss->frames->fromrp, 1);
                           replace_replacement_point_println(rp, 1); );
 
+               es->code = ss->frames->tocode;
                prevframe = ss->frames;
 
-               replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
+#if defined(ENABLE_VMLOG)
+               vmlog_cacao_rerol_method(ss->frames->method);
+#endif
 
-               if (ss->frames == NULL)
-                       break;
+               replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
 
-               DOLOG( replace_executionstate_println(es); );
+               DOLOG( executionstate_println(es); );
 
                if (rp->type == RPLPOINT_TYPE_CALL) {
-
-                       DOLOG( printf("pushing activation record for:\n");
-                                  replace_replacement_point_println(rp, 1); );
-
-                       replace_push_activation_record(es, rp, prevframe, ss->frames);
+                       parent = NULL;
+               }
+               else {
+                       /* inlining */
+                       parent = rp;
                }
-
-               DOLOG( replace_executionstate_println(es); );
        }
 }
 
 
-/* replace_build_execution_state ***********************************************
-
-   This function contains the final phase of replacement. It builds the new
-   execution state, releases dump memory, and returns to the calling
-   assembler function which finishes replacement.
-
-   NOTE: This function is called from asm_replacement_in, with the stack
-         pointer at the start of the safe stack area.
+/* replace_me ******************************************************************
+   This function is called by the signal handler when a thread reaches
+   a replacement point. `replace_me` must map the execution state to the
+   target replacement point and let execution continue there.
 
    THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
 
-   CAUTION: This function and its children must not use a lot of stack!
-            There are only REPLACE_SAFESTACK_SIZE bytes of C stack
-                       available.
-
    IN:
-       st...............the safestack contained the necessary data
-
+       rp...............replacement point that has been reached
+       es...............execution state read by signal handler
+  
 *******************************************************************************/
 
-void replace_build_execution_state(replace_safestack_t *st)
+static void replace_me(rplpoint *rp, executionstate_t *es)
 {
-       replace_build_execution_state_intern(st->ss, &(st->es));
+       stackframeinfo_t    *sfi;
+       sourcestate_t       *ss;
+       sourceframe_t       *frame;
+       codeinfo            *origcode;
+       rplpoint            *origrp;
+#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
+       threadobject        *thread;
+#endif
+       int32_t              dumpmarker;
 
-       DOLOG( replace_executionstate_println(&(st->es)); );
+       origcode = es->code;
+       origrp   = rp;
 
-       /* release dump area */
+#if defined(ENABLE_TLH)
+       printf("Replacing in %s/%s\n", rp->method->clazz->name->text, rp->method->name->text);
+#endif
 
-       dump_release(st->dumpsize);
+       /*if (strcmp(rp->method->clazz->name->text, "antlr/AlternativeElement") == 0 && strcmp(rp->method->name->text, "getAutoGenType") ==0) opt_TraceReplacement = 2; else opt_TraceReplacement = 0;*/
 
-       /* new code is entered after returning */
+       DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
+                                stat_replacements, (void*)THREADOBJECT,
+                                rp->id, (void*)rp);
+                                method_println(es->code->m); );
 
-       DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
-}
+       DOLOG( replace_replacement_point_println(rp, 1); );
 
+       REPLACE_COUNT(stat_replacements);
 
-/* replace_alloc_safestack *****************************************************
+       /* mark start of dump memory area */
 
-   Allocate a safe stack area to use during the final phase of replacement.
-   The returned area is not initialized. This must be done by the caller.
+       DMARKER;
 
-   RETURN VALUE:
-       a newly allocated replace_safestack_t *
+       /* Get the stackframeinfo for the current thread. */
 
-*******************************************************************************/
+       sfi = threads_get_current_stackframeinfo();
 
-static replace_safestack_t *replace_alloc_safestack()
-{
-       u1 *mem;
-       replace_safestack_t *st;
+       /* recover source state */
 
-       mem = MNEW(u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
+       ss = replace_recover_source_state(rp, sfi, es);
 
-       st = (replace_safestack_t *) ((ptrint)(mem + REPLACE_STACK_ALIGNMENT - 1)
-                                                                               & ~(REPLACE_STACK_ALIGNMENT - 1));
+#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
+       /* if there is a collection pending, we assume the replacement point should
+          suspend this thread */
 
-#if !defined(NDEBUG)
-       memset(st, 0xa5, sizeof(replace_safestack_t));
-#endif
+       if (gc_pending) {
 
-       st->mem = mem;
+               thread = THREADOBJECT;
 
-       return st;
-}
+               DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
 
+               /* map the sourcestate using the identity mapping */
+               replace_map_source_state_identity(ss);
 
-/* replace_free_safestack ******************************************************
+               /* since we enter the same method again, we turn off rps now */
+               /* XXX michi: can we really do this? what if the rp was active before
+                  we activated it for the gc? */
+               replace_deactivate_replacement_points(origcode);
 
-   Free the given safestack structure, making a copy of the contained
-   execution state before freeing it.
+               /* remember executionstate and sourcestate for this thread */
+               GC_EXECUTIONSTATE = es;
+               GC_SOURCESTATE    = ss;
 
-   NOTE: This function is called from asm_replacement_in.
+               /* really suspend this thread now (PC = 0) */
+               threads_suspend_ack(NULL, NULL);
 
-   IN:
-       st...............the safestack to free
-          tmpes............where to copy the execution state to
+               DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
 
-   OUT:
-          *tmpes...........receives a copy of st->es
+       } else {
+#endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
 
-*******************************************************************************/
+       /* map the source state */
 
-void replace_free_safestack(replace_safestack_t *st, executionstate_t *tmpes)
-{
-       u1 *mem;
+       if (!replace_map_source_state(ss))
+               vm_abort("exception during method replacement");
+
+       DOLOG( replace_sourcestate_println(ss); );
 
-       /* copy the executionstate_t to the temporary location */
+       DOLOG_SHORT( replace_sourcestate_println_short(ss); );
 
-       *tmpes = st->es;
+#if !defined(NDEBUG)
+       /* avoid infinite loops by self-replacement, only if not in testing mode */
+
+       if (!opt_TestReplacement) {
+               frame = ss->frames;
+               while (frame->down)
+                       frame = frame->down;
+
+               if (frame->torp == origrp) {
+                       DOLOG_SHORT(
+                               printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
+                       );
+                       replace_deactivate_replacement_points(origcode);
+               }
+       }
+#endif
 
-       /* get the memory address to free */
+#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
+       }
+#endif
 
-       mem = st->mem;
+       /* build the new execution state */
 
-       /* destroy memory (in debug mode) */
+       replace_build_execution_state(ss, es);
 
 #if !defined(NDEBUG)
-       memset(st, 0xa5, sizeof(replace_safestack_t));
+       /* continue execution after patched machine code, if testing mode enabled */
+
+       if (opt_TestReplacement)
+               es->pc += REPLACEMENT_PATCH_SIZE;
 #endif
 
-       /* free the safe stack struct */
+       /* release dump area */
 
-       MFREE(mem, u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
+       DRELEASE;
 }
 
 
-/* replace_me ******************************************************************
-   This function is called by asm_replacement_out when a thread reaches
-   a replacement point. `replace_me` must map the execution state to the
-   target replacement point and let execution continue there.
+/* replace_me_wrapper **********************************************************
+
+   This function is called by the signal handler. It determines if there
+   is an active replacement point pending at the given PC and returns
+   accordingly.
+
+   THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
 
-   This function never returns!
-  
    IN:
-       rp...............replacement point that has been reached
-          es...............execution state read by asm_replacement_out
-  
+       pc...............the program counter that triggered the replacement.
+       context..........the context (machine state) to which the
+                           replacement should be applied.
+
+   OUT:
+       context..........the context after replacement finished.
+
+   RETURN VALUE:
+       true.............replacement done, everything went ok
+       false............no replacement done, context unchanged
+
 *******************************************************************************/
 
-void replace_me(rplpoint *rp, executionstate_t *es)
+bool replace_me_wrapper(u1 *pc, void *context)
 {
-       sourcestate_t       *ss;
-       sourceframe_t       *frame;
-       s4                   dumpsize;
-       rplpoint            *origrp;
-       replace_safestack_t *safestack;
+       codeinfo         *code;
+       rplpoint         *rp;
+       executionstate_t  es;
+#if defined(ENABLE_RT_TIMING)
+       struct timespec time_start, time_end;
+#endif
 
-       origrp = rp;
-       es->code = code_find_codeinfo_for_pc(rp->pc);
+       /* search the codeinfo for the given PC */
 
-       DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
-                                stat_replacements, (void*)THREADOBJECT,
-                                rp->id, (void*)rp);
-                                method_println(es->code->m); );
+       code = code_find_codeinfo_for_pc(pc);
+       assert(code);
 
-       DOLOG( replace_replacement_point_println(rp, 1);
-                  replace_executionstate_println(es); );
+       /* search for a replacement point at the given PC */
 
-       REPLACE_COUNT(stat_replacements);
+       rp = replace_find_replacement_point_for_pc(code, pc, (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN));
 
-       /* mark start of dump memory area */
+       /* check if the replacement point belongs to given PC and is active */
 
-       dumpsize = dump_size();
+       if ((rp != NULL) && (rp->pc == pc)
+           && (rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))) {
 
-       /* recover source state */
+               DOLOG( printf("valid replacement point\n"); );
 
-       ss = replace_recover_source_state(rp, es);
+#if !defined(NDEBUG)
+               executionstate_sanity_check(context);
+#endif
 
-       /* map the source state */
+               /* set codeinfo pointer in execution state */
 
-       if (!replace_map_source_state(es->code, ss))
-               vm_abort("exception during method replacement");
+               es.code = code;
 
-       DOLOG( replace_sourcestate_println(ss); );
+               /* read execution state from current context */
 
-       DOLOG_SHORT( replace_sourcestate_println_short(ss); );
+               md_executionstate_read(&es, context);
 
-       /* avoid infinite loops by self-replacement */
+               DOLOG( printf("REPLACEMENT READ: ");
+                          executionstate_println(&es); );
 
-       frame = ss->frames;
-       while (frame->down)
-               frame = frame->down;
+               /* do the actual replacement */
+
+#if defined(ENABLE_RT_TIMING)
+               RT_TIMING_GET_TIME(time_start);
+#endif
+
+               replace_me(rp, &es);
+
+#if defined(ENABLE_RT_TIMING)
+               RT_TIMING_GET_TIME(time_end);
+               RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_REPLACE);
+#endif
 
-       if (frame->torp == origrp) {
-               DOLOG_SHORT(
-                       printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
-               );
-               replace_deactivate_replacement_points(frame->tocode);
+               /* write execution state to current context */
+
+               md_executionstate_write(&es, context);
+
+               DOLOG( printf("REPLACEMENT WRITE: ");
+                          executionstate_println(&es); );
+
+               /* new code is entered after returning */
+
+               DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
+               return true;
        }
+       else
+               return false;
+}
+
 
-       /* write execution state of new code */
+/******************************************************************************/
+/* NOTE: Stuff specific to the exact GC is below.                             */
+/******************************************************************************/
+
+#if defined(ENABLE_GC_CACAO)
+void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
+{
+       stackframeinfo_t *sfi;
+       executionstate_t *es;
+       sourcestate_t    *ss;
 
-       DOLOG( replace_executionstate_println(es); );
+       /* Get the stackframeinfo of this thread. */
 
-       /* allocate a safe stack area and copy all needed data there */
+       assert(thread == THREADOBJECT);
 
-       safestack = replace_alloc_safestack();
+       sfi = threads_get_current_stackframeinfo();
 
-       safestack->es = *es;
-       safestack->ss = ss;
-       safestack->dumpsize = dumpsize;
+       /* create the execution state */
+       es = DNEW(executionstate_t);
+       es->pc = pc;
+       es->sp = sp;
+       es->pv = 0;      /* since we are in a native, PV is invalid! */
+       es->code = NULL; /* since we are in a native, we do not have a codeinfo */
 
-       /* call the assembler code for the last phase of replacement */
+       /* we assume we are in a native (no replacement point)! */
+       ss = replace_recover_source_state(NULL, sfi, es);
 
-#if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
-       asm_replacement_in(&(safestack->es), safestack);
+       /* map the sourcestate using the identity mapping */
+       replace_map_source_state_identity(ss);
+
+       /* remember executionstate and sourcestate for this thread */
+       GC_EXECUTIONSTATE = es;
+       GC_SOURCESTATE    = ss;
+}
 #endif
 
-       abort(); /* NOT REACHED */
+#if defined(ENABLE_GC_CACAO)
+void replace_gc_into_native(threadobject *thread)
+{
+       executionstate_t *es;
+       sourcestate_t    *ss;
+
+       /* get the executionstate and sourcestate for the given thread */
+       es = GC_EXECUTIONSTATE;
+       ss = GC_SOURCESTATE;
+
+       /* rebuild the stack of the given thread */
+       replace_build_execution_state(ss, es);
 }
+#endif
 
 
 /******************************************************************************/
@@ -2408,6 +3265,8 @@ void replace_replacement_point_println(rplpoint *rp, int depth)
                        replace_type_str[rp->type]);
        if (rp->flags & RPLPOINT_FLAG_NOTRAP)
                printf(" NOTRAP");
+       if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
+               printf(" COUNTDOWN");
        if (rp->flags & RPLPOINT_FLAG_ACTIVE)
                printf(" ACTIVE");
        printf(" parent:%p\n", (void*)rp->parent);
@@ -2472,6 +3331,9 @@ void replace_show_replacement_points(codeinfo *code)
        printf("\ttotal allocations : %d\n",code->regalloccount);
        printf("\tsaved int regs    : %d\n",code->savedintcount);
        printf("\tsaved flt regs    : %d\n",code->savedfltcount);
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+       printf("\tsaved adr regs    : %d\n",code->savedadrcount);
+#endif
        printf("\tmemuse            : %d\n",code->memuse);
 
        printf("\n");
@@ -2491,124 +3353,42 @@ void replace_show_replacement_points(codeinfo *code)
 #endif
 
 
-/* replace_executionstate_println **********************************************
-   Print execution state
-  
-   IN:
-       es...............the execution state to print
-  
-*******************************************************************************/
-
-#if !defined(NDEBUG)
-void replace_executionstate_println(executionstate_t *es)
-{
-       int i;
-       int slots;
-       stackslot_t *sp;
-       int extraslots;
-
-       if (!es) {
-               printf("(executionstate_t *)NULL\n");
-               return;
-       }
-
-       printf("executionstate_t:\n");
-       printf("\tpc = %p",(void*)es->pc);
-       printf("  sp = %p",(void*)es->sp);
-       printf("  pv = %p\n",(void*)es->pv);
-#if defined(ENABLE_DISASSEMBLER)
-       for (i=0; i<INT_REG_CNT; ++i) {
-               if (i%4 == 0)
-                       printf("\t");
-               else
-                       printf(" ");
-#if SIZEOF_VOID_P == 8
-               printf("%-3s = %016llx",regs[i],(unsigned long long)es->intregs[i]);
-#else
-               printf("%-3s = %08lx",regs[i],(unsigned long)es->intregs[i]);
-#endif
-               if (i%4 == 3)
-                       printf("\n");
-       }
-       for (i=0; i<FLT_REG_CNT; ++i) {
-               if (i%4 == 0)
-                       printf("\t");
-               else
-                       printf(" ");
-               printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
-               if (i%4 == 3)
-                       printf("\n");
-       }
-#endif
-
-       sp = (stackslot_t *) es->sp;
-
-       extraslots = 2;
-
-       if (es->code) {
-               methoddesc *md = es->code->m->parseddesc;
-               slots = code_get_stack_frame_size(es->code);
-               extraslots = 1 + md->memuse;
-       }
-       else
-               slots = 0;
-
-
-       if (slots) {
-               printf("\tstack slots(+%d) at sp:", extraslots);
-               for (i=0; i<slots+extraslots; ++i) {
-                       if (i%4 == 0)
-                               printf("\n\t\t");
-                       printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
-#ifdef HAS_4BYTE_STACKSLOT
-                       printf("%08lx",(unsigned long)*sp++);
-#else
-                       printf("%016llx",(unsigned long long)*sp++);
-#endif
-                       printf("%c", (i >= slots) ? ')' : ' ');
-               }
-               printf("\n");
-       }
-
-       printf("\tcode: %p", (void*)es->code);
-       if (es->code != NULL) {
-               printf(" stackframesize=%d ", es->code->stackframesize);
-               method_print(es->code->m);
-       }
-       printf("\n");
-
-       printf("\n");
-}
-#endif
-
 #if !defined(NDEBUG)
-static void java_value_print(s4 type, u8 value)
+static void java_value_print(s4 type, replace_val_t value)
 {
-       java_objectheader *obj;
-       utf               *u;
+       java_object_t *obj;
+       utf           *u;
 
-       printf("%016llx",(unsigned long long) value);
+       printf("%016llx",(unsigned long long) value.l);
 
        if (type < 0 || type > TYPE_RET)
                printf(" <INVALID TYPE:%d>", type);
        else
                printf(" %s", show_jit_type_names[type]);
 
-       if (type == TYPE_ADR && value != 0) {
-               obj = (java_objectheader *) (ptrint) value;
+       if (type == TYPE_ADR && value.a != NULL) {
+               obj = value.a;
                putchar(' ');
-               utf_display_printable_ascii_classname(obj->vftbl->class->name);
+               utf_display_printable_ascii_classname(obj->vftbl->clazz->name);
 
-               if (obj->vftbl->class == class_java_lang_String) {
+               if (obj->vftbl->clazz == class_java_lang_String) {
                        printf(" \"");
-                       u = javastring_toutf((java_lang_String *)obj, false);
+                       u = javastring_toutf(obj, false);
                        utf_display_printable_ascii(u);
                        printf("\"");
                }
        }
-       else if (type == TYPE_INT || type == TYPE_LNG) {
-               printf(" %lld", (long long) value);
+       else if (type == TYPE_INT) {
+               printf(" %ld", (long) value.i);
+       }
+       else if (type == TYPE_LNG) {
+               printf(" %lld", (long long) value.l);
+       }
+       else if (type == TYPE_FLT) {
+               printf(" %f", value.f);
+       }
+       else if (type == TYPE_DBL) {
+               printf(" %f", value.d);
        }
 }
 #endif /* !defined(NDEBUG) */
@@ -2617,16 +3397,38 @@ static void java_value_print(s4 type, u8 value)
 #if !defined(NDEBUG)
 void replace_source_frame_println(sourceframe_t *frame)
 {
-       s4 i;
+       s4 i,j;
        s4 t;
 
+       if (REPLACE_IS_NATIVE_FRAME(frame)) {
+               printf("\tNATIVE\n");
+               printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
+               printf("\tnativepc: %p\n", frame->nativepc);
+               printf("\tframesize: %d\n", frame->nativeframesize);
+
+               j = 0;
+               for (i=0; i<INT_REG_CNT; ++i) {
+                       if (nregdescint[i] == REG_SAV)
+                               printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
+               }
+
+               j = 0;
+               for (i=0; i<FLT_REG_CNT; ++i) {
+                       if (nregdescfloat[i] == REG_SAV)
+                               printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
+               }
+
+               printf("\n");
+               return;
+       }
+
        printf("\t");
        method_println(frame->method);
        printf("\tid: %d\n", frame->id);
        printf("\ttype: %s\n", replace_type_str[frame->type]);
        printf("\n");
 
-       if (frame->instance) {
+       if (frame->instance.a) {
                printf("\tinstance: ");
                java_value_print(TYPE_ADR, frame->instance);
                printf("\n");
@@ -2669,9 +3471,9 @@ void replace_source_frame_println(sourceframe_t *frame)
                for (i=0; i<frame->syncslotcount; ++i) {
                        printf("\tslot[%2d] = ",i);
 #ifdef HAS_4BYTE_STACKSLOT
-                       printf("%08lx\n",(unsigned long) frame->syncslots[i]);
+                       printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
 #else
-                       printf("%016llx\n",(unsigned long long) frame->syncslots[i]);
+                       printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
 #endif
                }
                printf("\n");
@@ -2747,6 +3549,13 @@ void replace_sourcestate_println_short(sourcestate_t *ss)
        for (frame = ss->frames; frame != NULL; frame = frame->down) {
                printf("\t");
 
+               if (REPLACE_IS_NATIVE_FRAME(frame)) {
+                       printf("NATIVE (pc %p size %d) ",
+                                  (void*)frame->nativepc, frame->nativeframesize);
+                       replace_stackframeinfo_println(frame->sfi);
+                       continue;
+               }
+
                if (frame->torp) {
                        printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
                }
@@ -2768,6 +3577,21 @@ void replace_sourcestate_println_short(sourcestate_t *ss)
 }
 #endif
 
+#if !defined(NDEBUG)
+static void replace_stackframeinfo_println(stackframeinfo_t *sfi)
+{
+       printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
+                       (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
+                       (void*)sfi->ra, (void*)sfi->xpc);
+
+       if (sfi->code)
+               method_println(sfi->code->m);
+       else
+               printf("(nil)\n");
+}
+#endif
+
+
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where