#include "vm/types.h"
#include <assert.h>
+#include <stdint.h>
#include <stdlib.h>
#include "arch.h"
#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)
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)
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(__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;
}
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;
/* 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);
#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 */
/* 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 */
(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);
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;
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);
}
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);
/* 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 */
#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 */
/* 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 *rp;
s4 i;
- DOLOG( printf("searching for rp in %p ", (void*)code);
- method_println(code->m);
- printf("PC = %p\n", (void*)pc); );
+ 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) {
DOLOG( replace_replacement_point_println(rp, 2); );
- if (rp->pc <= pc)
+ if (rp->pc <= pc && rp->pc + rp->callsize >= pc)
found = rp;
}
- assert(found == NULL || found->pc + found->callsize >= pc);
-
return found;
}
static void replace_pop_native_frame(executionstate_t *es,
sourcestate_t *ss,
- stackframeinfo *sfi)
+ stackframeinfo_t *sfi)
{
sourceframe_t *frame;
codeinfo *code;
# endif
#endif
- /* restore pv, pc, and sp */
-
- 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 */
-
- DOLOG( printf("PV = %p\n", (void*) es->pv); );
+ /* restore codeinfo of the native stub */
- assert(es->pv != NULL);
+ code = code_get_codeinfo_for_pv(sfi->pv);
- 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);
}
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);
*******************************************************************************/
sourcestate_t *replace_recover_source_state(rplpoint *rp,
- stackframeinfo *sfi,
+ stackframeinfo_t *sfi,
executionstate_t *es)
{
sourcestate_t *ss;
#endif
-/* replace_build_execution_state_intern ****************************************
+/* replace_build_execution_state ***********************************************
Build an execution state for the given (mapped) source state.
*******************************************************************************/
-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;
}
-/* 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.
-
- 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
-
-*******************************************************************************/
-
-void replace_build_execution_state(replace_safestack_t *st)
-{
- replace_build_execution_state_intern(st->ss, &(st->es));
-
- DOLOG( replace_executionstate_println(&(st->es)); );
-
- /* release dump area */
-
- dump_release(st->dumpsize);
-
- /* new code is entered after returning */
-
- DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
-}
-
-
-/* replace_alloc_safestack *****************************************************
-
- 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.
-
- RETURN VALUE:
- a newly allocated replace_safestack_t *
-
-*******************************************************************************/
-
-static replace_safestack_t *replace_alloc_safestack()
-{
- u1 *mem;
- replace_safestack_t *st;
-
- mem = MNEW(u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
-
- st = (replace_safestack_t *) ((ptrint)(mem + REPLACE_STACK_ALIGNMENT - 1)
- & ~(REPLACE_STACK_ALIGNMENT - 1));
-
-#if !defined(NDEBUG)
- memset(st, 0xa5, sizeof(replace_safestack_t));
-#endif
-
- st->mem = mem;
-
- return st;
-}
-
-
-/* replace_free_safestack ******************************************************
-
- Free the given safestack structure, making a copy of the contained
- execution state before freeing it.
-
- NOTE: This function is called from asm_replacement_in.
-
- IN:
- st...............the safestack to free
- tmpes............where to copy the execution state to
-
- OUT:
- *tmpes...........receives a copy of st->es
-
-*******************************************************************************/
-
-void replace_free_safestack(replace_safestack_t *st, executionstate_t *tmpes)
-{
- u1 *mem;
-
- /* copy the executionstate_t to the temporary location */
-
- *tmpes = st->es;
-
- /* get the memory address to free */
-
- mem = st->mem;
-
- /* destroy memory (in debug mode) */
-
-#if !defined(NDEBUG)
- memset(st, 0xa5, sizeof(replace_safestack_t));
-#endif
-
- /* free the safe stack struct */
-
- MFREE(mem, u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
-}
-
-
-/* replace_me_wrapper **********************************************************
-
- TODO: Document me!
-
-*******************************************************************************/
-
-bool replace_me_wrapper(u1 *pc)
-{
- codeinfo *code;
- rplpoint *rp;
- executionstate_t es;
-
- /* search the codeinfo for the given PC */
-
- code = code_find_codeinfo_for_pc(pc);
- assert(code);
-
- /* 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 */
-
- if (rp != NULL && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
-
- /*md_replace_executionstate_read(&es, context);*/
-
- replace_me(rp, &es);
-
- return true;
- }
- else
- return false;
-}
-
-
/* replace_me ******************************************************************
- This function is called by asm_replacement_out when a thread reaches
+ 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 never returns!
-
+ THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
+
IN:
rp...............replacement point that has been reached
- es...............execution state read by asm_replacement_out
+ es...............execution state read by signal handler
*******************************************************************************/
-void replace_me(rplpoint *rp, executionstate_t *es)
+static void replace_me(rplpoint *rp, executionstate_t *es)
{
- stackframeinfo *sfi;
+ stackframeinfo_t *sfi;
sourcestate_t *ss;
sourceframe_t *frame;
s4 dumpsize;
+ codeinfo *origcode;
rplpoint *origrp;
- replace_safestack_t *safestack;
#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
threadobject *thread;
#endif
- origrp = rp;
- es->code = code_find_codeinfo_for_pc(rp->pc);
+ origcode = es->code;
+ origrp = rp;
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); );
+ DOLOG( replace_replacement_point_println(rp, 1); );
REPLACE_COUNT(stat_replacements);
/* 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? */
- frame = ss->frames;
- while (frame->down)
- frame = frame->down;
- replace_deactivate_replacement_points(frame->tocode);
+ replace_deactivate_replacement_points(origcode);
/* remember executionstate and sourcestate for this thread */
GC_EXECUTIONSTATE = es;
DOLOG_SHORT( replace_sourcestate_println_short(ss); );
- /* avoid infinite loops by self-replacement */
+#if !defined(NDEBUG)
+ /* avoid infinite loops by self-replacement, only if not in testing mode */
- frame = ss->frames;
- while (frame->down)
- frame = frame->down;
+ 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(frame->tocode);
+ if (frame->torp == origrp) {
+ DOLOG_SHORT(
+ printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
+ );
+ replace_deactivate_replacement_points(origcode);
+ }
}
+#endif
#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
}
#endif
- /* write execution state of new code */
+ /* build the new execution state */
- DOLOG( replace_executionstate_println(es); );
+ replace_build_execution_state(ss, es);
- /* allocate a safe stack area and copy all needed data there */
+#if !defined(NDEBUG)
+ /* continue execution after patched machine code, if testing mode enabled */
- safestack = replace_alloc_safestack();
+ if (opt_TestReplacement)
+ es->pc += REPLACEMENT_PATCH_SIZE;
+#endif
+
+ /* release dump area */
- safestack->es = *es;
- safestack->ss = ss;
- safestack->dumpsize = dumpsize;
+ dump_release(dumpsize);
+}
- /* call the assembler code for the last phase of replacement */
-#if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
- /*asm_replacement_in(&(safestack->es), safestack);*/
-#endif
+/* replace_me_wrapper **********************************************************
- abort(); /* NOT REACHED */
+ 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, void *context)
+{
+ codeinfo *code;
+ rplpoint *rp;
+ executionstate_t es;
+
+ /* search the codeinfo for the given PC */
+
+ code = code_find_codeinfo_for_pc(pc);
+ assert(code);
+
+ /* search for a replacement point at the given PC */
+
+ rp = replace_find_replacement_point_for_pc(code, pc);
+
+ /* check if the replacement point belongs to given PC and is active */
+
+ if ((rp != NULL) && (rp->pc == pc) && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
+
+ /* set codeinfo pointer in execution state */
+
+ es.code = code;
+
+ /* read execution state from current context */
+
+ md_replace_executionstate_read(&es, context);
+
+ DOLOG( printf("REPLACEMENT READ: ");
+ replace_executionstate_println(&es); );
+
+ /* do the actual replacement */
+
+ replace_me(rp, &es);
+
+ /* write execution state to current context */
+
+ md_replace_executionstate_write(&es, context);
+
+ DOLOG( printf("REPLACEMENT WRITE: ");
+ replace_executionstate_println(&es); );
+
+ /* new code is entered after returning */
+
+ DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
+ return true;
+ }
+ else
+ return false;
}
#if defined(ENABLE_GC_CACAO)
void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
{
- stackframeinfo *sfi;
+ stackframeinfo_t *sfi;
executionstate_t *es;
sourcestate_t *ss;
}
#endif
+#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
+
/******************************************************************************/
/* NOTE: No important code below. */
#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");
}