-/* 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 **********************************/
/*** 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)
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++;
}
}
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)
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:
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 */
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:
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;
rplpoint *rp;
s4 i;
s4 count;
- s4 index;
u1 *savedmcode;
assert(code->savedmcode == NULL);
/* 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;
if (rp->flags & RPLPOINT_FLAG_NOTRAP)
continue;
- index--;
-
if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
continue;
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;
}
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;
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;
IN:
es...............execution state
- sp...............stack pointer of the execution state (XXX eliminate?)
ra...............allocation
javaval..........where to put the value
*******************************************************************************/
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
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];
}
}
}
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
*******************************************************************************/
/* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
};
+
static void replace_read_executionstate(rplpoint *rp,
executionstate_t *es,
sourcestate_t *ss,
/* 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) */
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--;
}
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) */
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++;
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++;
assert(count);
assert(ra->index == RPLALLOC_STACK);
- frame->javastack[i] = 0;
+ frame->javastack[i].l = 0;
frame->javastacktype[i] = TYPE_VOID;
count--;
i++;
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--;
}
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++;
}
/* 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
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 */
/* 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++;
}
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++;
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++;
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;
}
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);
/* 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++;
}
}
-/* 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 */
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 ");
}
}
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:
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);
+ }
}
s4 stacki;
rplalloc *ra;
+ assert(code);
assert(frame);
DOLOG( printf("searching replacement point for:\n");
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;
}
}
/* 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
*******************************************************************************/
-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 ************************************************
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:
*******************************************************************************/
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
/* 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 */
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) {
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");
frame, it is (re)compiled.
IN:
- firstcode........XXX temporary hack, will be removed
ss...............the source state
OUT:
*******************************************************************************/
-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;
#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;
}
}
}
-/* 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.
*******************************************************************************/
-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
/******************************************************************************/
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);
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");
#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) */
#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");
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");
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) ? '=' : '+');
}
}
#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