-/* 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,
+ Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
J. Wenninger, Institut f. Computersprachen - TU Wien
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- Contact: cacao@cacaojvm.org
-
- Authors: Edwin Steiner
-
- $Id$
-
*/
#include "config.h"
#include "arch.h"
#include "mm/memory.h"
+
+#include "threads/threads-common.h"
+
#include "toolbox/logging.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/jit.h"
+#include "vm/jit/md.h"
#include "vm/jit/methodheader.h"
+#include "vm/jit/replace.h"
+#include "vm/jit/show.h"
+#include "vm/jit/stack.h"
+
#include "vmcore/options.h"
#include "vmcore/classcache.h"
-#include "native/include/java_lang_String.h"
#define REPLACE_PATCH_DYNAMIC_CALL
/*#define REPLACE_PATCH_ALL*/
+#if defined(ENABLE_VMLOG)
+#include <vmlog_cacao.h>
+#endif
/*** architecture-dependent configuration *************************************/
#undef REPLACE_LEAFMETHODS_RA_REGISTER
#undef REPLACE_REG_RA
-/* i386 and x86_64 */
-#if defined(__I386__) || defined(__X86_64__)
+/* 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_LINKAGE_AREA
#define REPLACE_LEAFMETHODS_RA_REGISTER
#define REPLACE_REG_RA REG_ITMP3 /* the execution state has the LR in itmp3 */
+/* s390 */
+#elif defined(__S390__)
+#define REPLACE_RA_TOP_OF_FRAME
+#define REPLACE_REG_RA REG_ITMP3
#endif
/*** debugging ****************************************************************/
-/*#define REPLACE_VERBOSE*/
-
#if !defined(NDEBUG)
static void java_value_print(s4 type, replace_val_t value);
static void replace_stackframeinfo_println(stackframeinfo *sfi);
#endif
-#if !defined(NDEBUG) && defined(REPLACE_VERBOSE)
-int replace_verbose = 0;
-#define DOLOG(code) do{ if (replace_verbose > 1) { code; } } while(0)
-#define DOLOG_SHORT(code) do{ if (replace_verbose > 0) { 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++;
}
}
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 */
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;
savedmcode -= REPLACEMENT_PATCH_SIZE;
-#if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
+#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);
#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)
+#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);
#endif
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,
replace_val_t *javaval)
{
/* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
#ifdef HAS_4BYTE_STACKSLOT
if (IS_2_WORD_TYPE(ra->type)) {
- javaval->l = *(u8*)(sp + ra->regoff);
+ javaval->l = *(u8*)(es->sp + ra->regoff);
}
else {
#endif
- javaval->p = sp[ra->regoff];
+ javaval->p = *(ptrint*)(es->sp + ra->regoff);
#ifdef HAS_4BYTE_STACKSLOT
}
#endif
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 {
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
if (ra->type == TYPE_LNG) {
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,
replace_val_t *javaval)
{
/* 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->l;
+ *(u8*)(es->sp + ra->regoff) = javaval->l;
}
else {
#endif
- sp[ra->regoff] = javaval->p;
+ *(ptrint*)(es->sp + ra->regoff) = javaval->p;
#ifdef HAS_4BYTE_STACKSLOT
}
#endif
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
+ ss->frames.......set to new frame (the new head of the frame list).
RETURN VALUE:
returns the new frame
/* replace_read_executionstate *************************************************
- Read the given executions state and translate it to a source frame.
+ 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
*******************************************************************************/
/* calculate base stack pointer */
- basesp = sp + code_get_stack_frame_size(code);
+ basesp = sp + code->stackframesize;
/* create the source frame */
if (ra->type == TYPE_RET)
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
}
#endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
calleeframe->syncslotcount = 1;
calleeframe->syncslots = DMNEW(replace_val_t, 1);
- replace_read_value(es,sp,ra,calleeframe->syncslots);
+ replace_read_value(es,ra,calleeframe->syncslots);
}
frame->javastackdepth--;
if (ra->type == TYPE_RET)
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(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;
}
/* 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++;
}
es->fltregs[reg] = *(double*)basesp;
}
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+ /* restore saved adr registers */
+
+ 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;
for (i=0; i<FLT_REG_CNT; ++i)
if (nregdescfloat[i] != REG_SAV)
*(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 (code) ? ra : NULL;
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] == (methodptr) pd->oldentrypoint)
+ && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
+ && METHOD_OF_CODE(vftbl->table[pd->m->vftblindex]) == pd->m)
{
replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
}
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);
sourceframe_t *callerframe,
sourceframe_t *calleeframe)
{
- u1 *patchpos;
- methodptr entrypoint;
- methodptr oldentrypoint;
- bool atentry;
- stackframeinfo sfi;
- codeinfo *calleecode;
- methodinfo *calleem;
- java_objectheader *obj;
- vftbl_t *vftbl;
+ u1 *patchpos;
+ methodptr entrypoint;
+ methodptr oldentrypoint;
+ bool atentry;
+ stackframeinfo sfi;
+ codeinfo *calleecode;
+ methodinfo *calleem;
+ java_object_t *obj;
+ vftbl_t *vftbl;
assert(ra);
assert(callerframe->down == calleeframe);
#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
+
/* write slots used for synchronization */
count = code_get_sync_slot_count(calleecode);
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 0
if (nregdescfloat[i] == REG_SAV)
es->fltregs[i] = 0.0;
}
+
+# if defined(HAS_ADDRESS_REGISTER_FILE)
+ for (i=0; i<ADR_REG_CNT; ++i) {
+ if (nregdescadr[i] == REG_SAV)
+ es->adrregs[i] = 0;
+ }
+# endif
#endif
/* restore pv, pc, and sp */
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;
/* get the stackframeinfo if none is given */
if (sfi == NULL)
- sfi = *(STACKFRAMEINFO);
+ sfi = STACKFRAMEINFO;
/* each iteration of the loop recovers one source frame */
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++;
#if defined(REPLACE_STATISTICS)
oldcode = frame->method->code;
#endif
+ /* request optimization of hot methods and their callers */
+
+ if (frame->method->hitcountdown < 0
+ || (frame->down && frame->down->method->hitcountdown < 0))
+ jit_request_optimization(frame->method);
+
code = jit_get_current_code(frame->method);
if (code == NULL)
es->code = ss->frames->tocode;
prevframe = ss->frames;
+
+#if defined(ENABLE_VMLOG)
+ vmlog_cacao_rerol_method(ss->frames->method);
+#endif
+
replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
DOLOG( replace_executionstate_println(es); );
}
+/* 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
/* call the assembler code for the last phase of replacement */
-#if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
- asm_replacement_in(&(safestack->es), safestack);
+#if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
+ /*asm_replacement_in(&(safestack->es), safestack);*/
#endif
abort(); /* NOT REACHED */
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");
else
printf(" ");
#if SIZEOF_VOID_P == 8
- printf("%-3s = %016llx",regs[i],(unsigned long long)es->intregs[i]);
+ printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
#else
- printf("%-3s = %08lx",regs[i],(unsigned long)es->intregs[i]);
+ printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
#endif
if (i%4 == 3)
printf("\n");
if (i%4 == 3)
printf("\n");
}
+# if defined(HAS_ADDRESS_REGISTER_FILE)
+ for (i=0; i<ADR_REG_CNT; ++i) {
+ if (i%4 == 0)
+ printf("\t");
+ else
+ printf(" ");
+ printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
+ if (i%4 == 3)
+ printf("\n");
+ }
+# endif
#endif
sp = (stackslot_t *) es->sp;
if (es->code) {
methoddesc *md = es->code->m->parseddesc;
- slots = code_get_stack_frame_size(es->code);
+ slots = es->code->stackframesize;
extraslots = 1 + md->memuse;
}
else
#if !defined(NDEBUG)
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.l);
if (obj->vftbl->class == class_java_lang_String) {
printf(" \"");
- u = javastring_toutf((java_lang_String *)obj, false);
+ u = javastring_toutf(obj, false);
utf_display_printable_ascii(u);
printf("\"");
}
j = 0;
for (i=0; i<INT_REG_CNT; ++i) {
if (nregdescint[i] == REG_SAV)
- printf("\t%s = %p\n", regs[i], (void*)frame->nativesavint[j++]);
+ printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
}
j = 0;