* Merged executionstate branch.
[cacao.git] / src / vm / jit / replace.c
index 03969f4a6125b2fcbb3ce0235002ae29d050b437..5895bec0688a9368f4e8491e57c582ef0bf5be16 100644 (file)
@@ -1,9 +1,7 @@
 /* src/vm/jit/replace.c - on-stack replacement of methods
 
-   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
-   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
-   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
-   J. Wenninger, Institut f. Computersprachen - TU Wien
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
 #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/threads-common.h"
+#include "threads/thread.h"
 
 #include "toolbox/logging.h"
 
@@ -43,8 +47,8 @@
 #include "vm/jit/abi.h"
 #include "vm/jit/asmpart.h"
 #include "vm/jit/disass.h"
+#include "vm/jit/executionstate.h"
 #include "vm/jit/jit.h"
-#include "vm/jit/md.h"
 #include "vm/jit/methodheader.h"
 #include "vm/jit/replace.h"
 #include "vm/jit/show.h"
@@ -109,7 +113,7 @@ typedef u8 stackslot_t;
 
 #if !defined(NDEBUG)
 static void java_value_print(s4 type, replace_val_t value);
-static void replace_stackframeinfo_println(stackframeinfo *sfi);
+static void replace_stackframeinfo_println(stackframeinfo_t *sfi);
 #endif
 
 #if !defined(NDEBUG)
@@ -424,11 +428,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)
@@ -473,6 +472,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:
@@ -624,6 +634,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:
@@ -777,7 +800,6 @@ void replace_activate_replacement_points(codeinfo *code, bool mappable)
        rplpoint *rp;
        s4        i;
        s4        count;
-       s4        index;
        u1       *savedmcode;
 
        assert(code->savedmcode == NULL);
@@ -785,15 +807,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;
 
@@ -817,8 +836,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;
 
@@ -827,9 +844,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(__S390__)) && 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;
        }
 
@@ -889,8 +917,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(__S390__)) && 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;
@@ -1479,14 +1517,14 @@ u1* replace_pop_activation_record(executionstate_t *es,
        /* read the return address */
 
 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
-       if (CODE_IS_LEAFMETHOD(es->code))
+       if (code_is_leafmethod(es->code))
                ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
        else
 #endif
                ra = md_stacktrace_get_returnaddress(es->sp,
                                SIZE_OF_STACKSLOT * es->code->stackframesize);
 
-       DOLOG( printf("return address: %p\n", (void*)ra); );
+       DOLOG( printf("RA = %p\n", (void*)ra); );
 
        assert(ra);
 
@@ -1510,14 +1548,14 @@ u1* replace_pop_activation_record(executionstate_t *es,
 
 #if defined(REPLACE_RA_TOP_OF_FRAME)
 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
-       if (!CODE_IS_LEAFMETHOD(es->code))
+       if (!code_is_leafmethod(es->code))
 #endif
                es->intregs[REPLACE_REG_RA] = *--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))
+       if (!code_is_leafmethod(es->code))
 #endif
                es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
 #endif /* REPLACE_RA_LINKAGE_AREA */
@@ -1569,14 +1607,9 @@ u1* replace_pop_activation_record(executionstate_t *es,
        /* find the new codeinfo */
 
        pv = md_codegen_get_pv_from_pc(ra);
-
        DOLOG( printf("PV = %p\n", (void*) pv); );
 
-       if (pv == NULL) /* XXX can this really happen? */
-               return NULL;
-
-       code = *(codeinfo **)(pv + CodeinfoPointer);
-
+       code = code_get_codeinfo_for_pv(pv);
        DOLOG( printf("CODE = %p\n", (void*) code); );
 
        /* return NULL if we reached native code */
@@ -1634,8 +1667,8 @@ static void replace_patch_method_pointer(methodptr *mpp,
                                  (void*) *mpp, (void*)entrypoint); );
 
 #if !defined(NDEBUG)
-       oldcode = *(codeinfo **)((u1*)(*mpp) + CodeinfoPointer);
-       newcode = *(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer);
+       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);
@@ -1710,12 +1743,6 @@ struct replace_patch_data_t {
        u1         *entrypoint;
 };
 
-#define CODEINFO_OF_CODE(entrypoint) \
-       (*(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer))
-
-#define METHOD_OF_CODE(entrypoint) \
-       (CODEINFO_OF_CODE(entrypoint)->m)
-
 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
 {
        vftbl_t *vftbl = c->vftbl;
@@ -1723,7 +1750,7 @@ void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
        if (vftbl != NULL
                && vftbl->vftbllength > pd->m->vftblindex
                && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
-               && METHOD_OF_CODE(vftbl->table[pd->m->vftblindex]) == pd->m)
+               && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
        {
                replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
        }
@@ -1764,15 +1791,15 @@ void replace_patch_future_calls(u1 *ra,
                                                                sourceframe_t *callerframe,
                                                                sourceframe_t *calleeframe)
 {
-       u1             *patchpos;
-       methodptr       entrypoint;
-       methodptr       oldentrypoint;
-       bool            atentry;
-       stackframeinfo  sfi;
-       codeinfo       *calleecode;
-       methodinfo     *calleem;
-       java_object_t  *obj;
-       vftbl_t        *vftbl;
+       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);
@@ -1795,8 +1822,8 @@ void replace_patch_future_calls(u1 *ra,
 
        /* get the position to patch, in case it was a statically bound call   */
 
-       sfi.pv = callerframe->fromcode->entrypoint;
-       patchpos = md_get_method_patch_address(ra, &sfi, NULL);
+       pv = callerframe->fromcode->entrypoint;
+       patchpos = md_jit_method_patch_address(pv, ra, NULL);
 
        if (patchpos == NULL) {
                /* the call was dispatched dynamically */
@@ -1823,9 +1850,9 @@ void replace_patch_future_calls(u1 *ra,
                obj = calleeframe->instance.a;
                vftbl = obj->vftbl;
 
-               assert(vftbl->class->vftbl == vftbl);
+               assert(vftbl->clazz->vftbl == vftbl);
 
-               DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
+               DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->clazz); );
 
                replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
        }
@@ -1932,14 +1959,14 @@ void replace_push_activation_record(executionstate_t *es,
 
 #if defined(REPLACE_RA_TOP_OF_FRAME)
 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
-       if (!CODE_IS_LEAFMETHOD(calleecode))
+       if (!code_is_leafmethod(calleecode))
 #endif
                *--basesp = (ptrint) ra;
 #endif /* REPLACE_RA_TOP_OF_FRAME */
 
 #if defined(REPLACE_RA_LINKAGE_AREA)
 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
-       if (!CODE_IS_LEAFMETHOD(calleecode))
+       if (!code_is_leafmethod(calleecode))
 #endif
                basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
 #endif /* REPLACE_RA_LINKAGE_AREA */
@@ -2103,7 +2130,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
@@ -2121,7 +2150,7 @@ rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
        rplpoint *rp;
        s4        i;
 
-       DOLOG( printf("searching for rp in %p ", (void*)code);
+       DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
                   method_println(code->m); );
 
        found = NULL;
@@ -2129,7 +2158,7 @@ rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
        rp = code->rplpoints;
        for (i=0; i<code->rplpointcount; ++i, ++rp) {
                DOLOG( replace_replacement_point_println(rp, 2); );
-               if (rp->pc <= pc)
+               if (rp->pc <= pc && rp->pc + rp->callsize >= pc)
                        found = rp;
        }
 
@@ -2155,7 +2184,7 @@ rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
 
 static void replace_pop_native_frame(executionstate_t *es,
                                                                         sourcestate_t *ss,
-                                                                        stackframeinfo *sfi)
+                                                                        stackframeinfo_t *sfi)
 {
        sourceframe_t *frame;
        codeinfo      *code;
@@ -2170,7 +2199,7 @@ static void replace_pop_native_frame(executionstate_t *es,
        /* remember pc and size of native frame */
 
        frame->nativepc = es->pc;
-       frame->nativeframesize = sfi->sp - es->sp;
+       frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
        assert(frame->nativeframesize >= 0);
 
        /* remember values of saved registers */
@@ -2197,20 +2226,36 @@ static void replace_pop_native_frame(executionstate_t *es,
 
        /* restore saved registers */
 
-#if 0
+#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(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;
@@ -2218,29 +2263,21 @@ static void replace_pop_native_frame(executionstate_t *es,
 # endif
 #endif
 
-       /* restore pv, pc, and sp */
+       /* restore codeinfo of the native stub */
 
-       if (sfi->pv == NULL) {
-               /* frame of a native function call */
-               es->pv = md_codegen_get_pv_from_pc(sfi->ra);
-       }
-       else {
-               es->pv = sfi->pv;
-       }
-       es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
-       es->sp = sfi->sp;
-
-       /* find the new codeinfo */
+       code = code_get_codeinfo_for_pv(sfi->pv);
 
-       DOLOG( printf("PV = %p\n", (void*) es->pv); );
-
-       assert(es->pv != NULL);
-
-       code = *(codeinfo **)(es->pv + CodeinfoPointer);
-
-       DOLOG( printf("CODE = %p\n", (void*) code); );
+       /* restore sp, pv, pc and codeinfo of the parent method */
 
-       es->code = code;
+       /* 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);
 }
 
 
@@ -2281,10 +2318,36 @@ static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
 
        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;
@@ -2333,7 +2396,7 @@ static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
 *******************************************************************************/
 
 sourcestate_t *replace_recover_source_state(rplpoint *rp,
-                                                                                       stackframeinfo *sfi,
+                                                                                       stackframeinfo_t *sfi,
                                                                                    executionstate_t *es)
 {
        sourcestate_t *ss;
@@ -2348,11 +2411,6 @@ sourcestate_t *replace_recover_source_state(rplpoint *rp,
        ss = DNEW(sourcestate_t);
        ss->frames = NULL;
 
-       /* get the stackframeinfo if none is given */
-
-       if (sfi == NULL)
-               sfi = STACKFRAMEINFO;
-
        /* each iteration of the loop recovers one source frame */
 
        depth = 0;
@@ -2360,7 +2418,7 @@ sourcestate_t *replace_recover_source_state(rplpoint *rp,
 
        while (rp || sfi) {
 
-               DOLOG( replace_executionstate_println(es); );
+               DOLOG( executionstate_println(es); );
 
                /* if we are not at a replacement point, it is a native frame */
 
@@ -2425,7 +2483,9 @@ sourcestate_t *replace_recover_source_state(rplpoint *rp,
 
                                rp = NULL;
 
+#if !defined(ENABLE_GC_CACAO)
                                break; /* XXX remove to activate native frames */
+#endif
                                continue;
                        }
 
@@ -2547,7 +2607,53 @@ static bool replace_map_source_state(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.
 
@@ -2565,8 +2671,8 @@ static bool replace_map_source_state(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;
@@ -2595,7 +2701,7 @@ static void replace_build_execution_state_intern(sourcestate_t *ss,
 
                        replace_push_activation_record(es, rp, prevframe, ss->frames);
 
-                       DOLOG( replace_executionstate_println(es); );
+                       DOLOG( executionstate_println(es); );
                }
 
                rp = ss->frames->torp;
@@ -2615,7 +2721,7 @@ static void replace_build_execution_state_intern(sourcestate_t *ss,
 
                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) {
                        parent = NULL;
@@ -2628,119 +2734,156 @@ static void replace_build_execution_state_intern(sourcestate_t *ss,
 }
 
 
-/* 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));
-
-       DOLOG( replace_executionstate_println(&(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;
 
-       /* release dump area */
+       origcode = es->code;
+       origrp   = rp;
 
-       dump_release(st->dumpsize);
+       DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
+                                stat_replacements, (void*)THREADOBJECT,
+                                rp->id, (void*)rp);
+                                method_println(es->code->m); );
 
-       /* new code is entered after returning */
+       DOLOG( replace_replacement_point_println(rp, 1); );
 
-       DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
-}
+       REPLACE_COUNT(stat_replacements);
 
+       /* mark start of dump memory area */
 
-/* replace_alloc_safestack *****************************************************
+       DMARKER;
 
-   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.
+       /* Get the stackframeinfo for the current thread. */
 
-   RETURN VALUE:
-       a newly allocated replace_safestack_t *
+       sfi = threads_get_current_stackframeinfo();
 
-*******************************************************************************/
+       /* recover source state */
 
-static replace_safestack_t *replace_alloc_safestack()
-{
-       u1 *mem;
-       replace_safestack_t *st;
+       ss = replace_recover_source_state(rp, sfi, es);
 
-       mem = MNEW(u1, sizeof(replace_safestack_t) + 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 */
 
-       st = (replace_safestack_t *) ((ptrint)(mem + REPLACE_STACK_ALIGNMENT - 1)
-                                                                               & ~(REPLACE_STACK_ALIGNMENT - 1));
+       if (gc_pending) {
 
-#if !defined(NDEBUG)
-       memset(st, 0xa5, sizeof(replace_safestack_t));
-#endif
+               thread = THREADOBJECT;
 
-       st->mem = mem;
+               DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
 
-       return st;
-}
+               /* map the sourcestate using the identity mapping */
+               replace_map_source_state_identity(ss);
 
+               /* 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);
 
-/* replace_free_safestack ******************************************************
+               /* remember executionstate and sourcestate for this thread */
+               GC_EXECUTIONSTATE = es;
+               GC_SOURCESTATE    = ss;
 
-   Free the given safestack structure, making a copy of the contained
-   execution state before freeing it.
+               /* really suspend this thread now (PC = 0) */
+               threads_suspend_ack(NULL, NULL);
 
-   NOTE: This function is called from asm_replacement_in.
+               DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
 
-   IN:
-       st...............the safestack to free
-          tmpes............where to copy the execution state to
+       } else {
+#endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
 
-   OUT:
-          *tmpes...........receives a copy of st->es
+       /* map the source state */
 
-*******************************************************************************/
+       if (!replace_map_source_state(ss))
+               vm_abort("exception during method replacement");
 
-void replace_free_safestack(replace_safestack_t *st, executionstate_t *tmpes)
-{
-       u1 *mem;
+       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_wrapper **********************************************************
 
-   TODO: Document me!
+   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!
+
+   IN:
+       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
 
 *******************************************************************************/
 
-bool replace_me_wrapper(u1 *pc)
+bool replace_me_wrapper(u1 *pc, void *context)
 {
        codeinfo         *code;
        rplpoint         *rp;
@@ -2753,121 +2896,98 @@ bool replace_me_wrapper(u1 *pc)
 
        /* search for a replacement point at the given PC */
 
-#if 0
        rp = replace_find_replacement_point_for_pc(code, pc);
-       assert(rp == NULL || rp->pc == pc);
-#else
-       {
-               int i;
-               rplpoint *rp2;
-               rp = NULL;
-               for (i=0,rp2=code->rplpoints; i<code->rplpointcount; i++,rp2++) {
-                       if (rp2->pc == pc)
-                               rp = rp2;
-               }
-       }
-#endif
 
-       /* check if the replacement point is active */
+       /* check if the replacement point belongs to given PC and is active */
 
-       if (rp != NULL && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
+       if ((rp != NULL) && (rp->pc == pc) && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
 
-               /*md_replace_executionstate_read(&es, context);*/
+#if !defined(NDEBUG)
+               executionstate_sanity_check(context);
+#endif
 
-               replace_me(rp, &es);
+               /* set codeinfo pointer in execution state */
 
-               return true;
-       }
-       else
-               return false;
-}
+               es.code = code;
 
+               /* read execution state from current context */
 
-/* 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.
+               md_executionstate_read(&es, context);
 
-   This function never returns!
-  
-   IN:
-       rp...............replacement point that has been reached
-          es...............execution state read by asm_replacement_out
-  
-*******************************************************************************/
+               DOLOG( printf("REPLACEMENT READ: ");
+                          executionstate_println(&es); );
 
-void replace_me(rplpoint *rp, executionstate_t *es)
-{
-       sourcestate_t       *ss;
-       sourceframe_t       *frame;
-       s4                   dumpsize;
-       rplpoint            *origrp;
-       replace_safestack_t *safestack;
-
-       origrp = rp;
-       es->code = code_find_codeinfo_for_pc(rp->pc);
+               /* do the actual replacement */
 
-       DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
-                                stat_replacements, (void*)THREADOBJECT,
-                                rp->id, (void*)rp);
-                                method_println(es->code->m); );
-
-       DOLOG( replace_replacement_point_println(rp, 1);
-                  replace_executionstate_println(es); );
-
-       REPLACE_COUNT(stat_replacements);
-
-       /* mark start of dump memory area */
+               replace_me(rp, &es);
 
-       dumpsize = dump_size();
+               /* write execution state to current context */
 
-       /* recover source state */
+               md_executionstate_write(&es, context);
 
-       ss = replace_recover_source_state(rp, NULL, es);
+               DOLOG( printf("REPLACEMENT WRITE: ");
+                          executionstate_println(&es); );
 
-       /* map the source state */
+               /* new code is entered after returning */
 
-       if (!replace_map_source_state(ss))
-               vm_abort("exception during method replacement");
+               DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
+               return true;
+       }
+       else
+               return false;
+}
 
-       DOLOG( replace_sourcestate_println(ss); );
 
-       DOLOG_SHORT( replace_sourcestate_println_short(ss); );
+/******************************************************************************/
+/* NOTE: Stuff specific to the exact GC is below.                             */
+/******************************************************************************/
 
-       /* avoid infinite loops by self-replacement */
+#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;
 
-       frame = ss->frames;
-       while (frame->down)
-               frame = frame->down;
+       /* Get the stackframeinfo of this thread. */
 
-       if (frame->torp == origrp) {
-               DOLOG_SHORT(
-                       printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
-               );
-               replace_deactivate_replacement_points(frame->tocode);
-       }
+       assert(thread == THREADOBJECT);
 
-       /* write execution state of new code */
+       sfi = threads_get_current_stackframeinfo();
 
-       DOLOG( replace_executionstate_println(es); );
+       /* 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 */
 
-       /* allocate a safe stack area and copy all needed data there */
+       /* we assume we are in a native (no replacement point)! */
+       ss = replace_recover_source_state(NULL, sfi, es);
 
-       safestack = replace_alloc_safestack();
+       /* map the sourcestate using the identity mapping */
+       replace_map_source_state_identity(ss);
 
-       safestack->es = *es;
-       safestack->ss = ss;
-       safestack->dumpsize = dumpsize;
+       /* remember executionstate and sourcestate for this thread */
+       GC_EXECUTIONSTATE = es;
+       GC_SOURCESTATE    = ss;
+}
+#endif
 
-       /* call the assembler code for the last phase of replacement */
+#if defined(ENABLE_GC_CACAO)
+void replace_gc_into_native(threadobject *thread)
+{
+       executionstate_t *es;
+       sourcestate_t    *ss;
 
-#if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
-       /*asm_replacement_in(&(safestack->es), safestack);*/
-#endif
+       /* get the executionstate and sourcestate for the given thread */
+       es = GC_EXECUTIONSTATE;
+       ss = GC_SOURCESTATE;
 
-       abort(); /* NOT REACHED */
+       /* rebuild the stack of the given thread */
+       replace_build_execution_state(ss, es);
 }
+#endif
 
 
 /******************************************************************************/
@@ -3107,108 +3227,6 @@ 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",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
-#else
-               printf("%-3s = %08lx",abi_registers_integer_name[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");
-       }
-# if defined(HAS_ADDRESS_REGISTER_FILE)
-       for (i=0; i<ADR_REG_CNT; ++i) {
-               if (i%4 == 0)
-                       printf("\t");
-               else
-                       printf(" ");
-               printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
-               if (i%4 == 3)
-                       printf("\n");
-       }
-# endif
-#endif
-
-       sp = (stackslot_t *) es->sp;
-
-       extraslots = 2;
-
-       if (es->code) {
-               methoddesc *md = es->code->m->parseddesc;
-               slots = es->code->stackframesize;
-               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, replace_val_t value)
 {
@@ -3225,9 +3243,9 @@ static void java_value_print(s4 type, replace_val_t 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(obj, false);
                        utf_display_printable_ascii(u);
@@ -3407,7 +3425,7 @@ void replace_sourcestate_println_short(sourcestate_t *ss)
 
                if (REPLACE_IS_NATIVE_FRAME(frame)) {
                        printf("NATIVE (pc %p size %d) ",
-                                       (void*)frame->nativepc, frame->nativeframesize);
+                                  (void*)frame->nativepc, frame->nativeframesize);
                        replace_stackframeinfo_println(frame->sfi);
                        continue;
                }
@@ -3434,19 +3452,20 @@ void replace_sourcestate_println_short(sourcestate_t *ss)
 #endif
 
 #if !defined(NDEBUG)
-static void replace_stackframeinfo_println(stackframeinfo *sfi)
+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->method)
-               method_println(sfi->method);
+       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