From: Christian Thalinger Date: Thu, 21 Aug 2008 15:42:40 +0000 (+0200) Subject: * src/vm/jit/replace.c: Moved to .cpp. X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=6662937568214dd15f634f552b271e166a465b91;p=cacao.git * src/vm/jit/replace.c: Moved to .cpp. * src/vm/jit/replace.h: Likewise. * src/vm/jit/replace.cpp: New file. * src/vm/jit/replace.hpp: Likewise. * src/mm/cacao-gc/gc.h, src/mm/cacao-gc/rootset.c, src/mm/cacao-gc/rootset.h, src/threads/posix/thread-posix.hpp, src/vm/jit/Makefile.am, src/vm/jit/alpha/codegen.c, src/vm/jit/alpha/emit.c, src/vm/jit/arm/emit.c, src/vm/jit/code.h, src/vm/jit/codegen-common.c, src/vm/jit/codegen-common.h, src/vm/jit/executionstate.h, src/vm/jit/i386/codegen.c, src/vm/jit/i386/emit.c, src/vm/jit/ir/instruction.hpp, src/vm/jit/jit.hpp, src/vm/jit/m68k/codegen.c, src/vm/jit/mips/codegen.c, src/vm/jit/mips/emit.c, src/vm/jit/powerpc/codegen.c, src/vm/jit/powerpc/emit.c, src/vm/jit/powerpc64/codegen.c, src/vm/jit/s390/codegen.c, src/vm/jit/s390/emit.c, src/vm/jit/sparc64/codegen.c, src/vm/jit/sparc64/emit.c, src/vm/jit/stacktrace.hpp, src/vm/jit/trap.c, src/vm/jit/x86_64/codegen.c, src/vm/jit/x86_64/emit.c: Changed include and other related fixes. --HG-- rename : src/vm/jit/replace.c => src/vm/jit/replace.cpp rename : src/vm/jit/replace.h => src/vm/jit/replace.hpp --- diff --git a/src/mm/cacao-gc/gc.h b/src/mm/cacao-gc/gc.h index fd42e44a4..d4a300946 100644 --- a/src/mm/cacao-gc/gc.h +++ b/src/mm/cacao-gc/gc.h @@ -38,7 +38,7 @@ #include "threads/thread.hpp" #include "toolbox/list.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" /* Configuration Switches *****************************************************/ diff --git a/src/mm/cacao-gc/rootset.c b/src/mm/cacao-gc/rootset.c index fe3253579..7761fa808 100644 --- a/src/mm/cacao-gc/rootset.c +++ b/src/mm/cacao-gc/rootset.c @@ -38,7 +38,7 @@ #include "toolbox/logging.h" #include "vm/global.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" diff --git a/src/mm/cacao-gc/rootset.h b/src/mm/cacao-gc/rootset.h index 5b0dc52b8..9267d7fdb 100644 --- a/src/mm/cacao-gc/rootset.h +++ b/src/mm/cacao-gc/rootset.h @@ -35,7 +35,7 @@ typedef struct rootset_t rootset_t; #include "vm/method.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" /* Structures *****************************************************************/ diff --git a/src/threads/posix/thread-posix.hpp b/src/threads/posix/thread-posix.hpp index e1e412ecb..a084bd924 100644 --- a/src/threads/posix/thread-posix.hpp +++ b/src/threads/posix/thread-posix.hpp @@ -56,7 +56,7 @@ typedef struct threadobject threadobject; #if defined(ENABLE_GC_CACAO) # include "vm/jit/executionstate.h" -# include "vm/jit/replace.h" +# include "vm/jit/replace.hpp" #endif #include "vm/jit/stacktrace.hpp" diff --git a/src/vm/jit/Makefile.am b/src/vm/jit/Makefile.am index 02535f30b..50ed6d505 100644 --- a/src/vm/jit/Makefile.am +++ b/src/vm/jit/Makefile.am @@ -103,7 +103,7 @@ REG_SOURCES = \ reg.h REPLACE_SOURCES += \ - replace.h + replace.hpp STACK_SOURCES = \ stack.c \ @@ -116,7 +116,7 @@ endif if ENABLE_REPLACEMENT REPLACE_SOURCES += \ - replace.c + replace.cpp endif if ENABLE_VERIFIER diff --git a/src/vm/jit/alpha/codegen.c b/src/vm/jit/alpha/codegen.c index 341bf901c..f176d8bba 100644 --- a/src/vm/jit/alpha/codegen.c +++ b/src/vm/jit/alpha/codegen.c @@ -60,7 +60,7 @@ #include "vm/jit/parse.h" #include "vm/jit/patcher-common.h" #include "vm/jit/reg.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/alpha/emit.c b/src/vm/jit/alpha/emit.c index eae793e6b..0fc5314db 100644 --- a/src/vm/jit/alpha/emit.c +++ b/src/vm/jit/alpha/emit.c @@ -46,7 +46,7 @@ #include "vm/jit/emit-common.h" #include "vm/jit/jit.hpp" #include "vm/jit/patcher-common.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/trace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/arm/emit.c b/src/vm/jit/arm/emit.c index 847e9c388..b3efb40d2 100644 --- a/src/vm/jit/arm/emit.c +++ b/src/vm/jit/arm/emit.c @@ -45,7 +45,7 @@ #include "vm/jit/emit-common.h" #include "vm/jit/jit.hpp" #include "vm/jit/patcher-common.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/trace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/code.h b/src/vm/jit/code.h index 918557594..c859984ca 100644 --- a/src/vm/jit/code.h +++ b/src/vm/jit/code.h @@ -41,7 +41,7 @@ #include "vm/jit/exceptiontable.h" #include "vm/jit/linenumbertable.h" #include "vm/jit/methodheader.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" /* constants ******************************************************************/ diff --git a/src/vm/jit/codegen-common.c b/src/vm/jit/codegen-common.c index 240bf1a78..0f2dd7419 100644 --- a/src/vm/jit/codegen-common.c +++ b/src/vm/jit/codegen-common.c @@ -88,7 +88,7 @@ #include "vm/jit/methodheader.h" #include "vm/jit/methodtree.h" #include "vm/jit/patcher-common.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #if defined(ENABLE_SSA) # include "vm/jit/optimizing/lsra.h" # include "vm/jit/optimizing/ssa.h" diff --git a/src/vm/jit/codegen-common.h b/src/vm/jit/codegen-common.h index 3b27daa3b..5235d149a 100644 --- a/src/vm/jit/codegen-common.h +++ b/src/vm/jit/codegen-common.h @@ -50,7 +50,7 @@ typedef struct linenumberref linenumberref; #include "vm/jit/jit.hpp" #include "vm/jit/reg.h" #include "vm/jit/code.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #define MCODEINITSIZE (1<<15) /* 32 Kbyte code area initialization size */ diff --git a/src/vm/jit/executionstate.h b/src/vm/jit/executionstate.h index 46211e722..4ae8ab6c2 100644 --- a/src/vm/jit/executionstate.h +++ b/src/vm/jit/executionstate.h @@ -68,6 +68,10 @@ struct executionstate_t { /* prototypes *****************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + #if !defined(NDEBUG) void executionstate_sanity_check(void *context); void executionstate_println(executionstate_t *es); @@ -78,6 +82,10 @@ void executionstate_println(executionstate_t *es); void md_executionstate_read(executionstate_t *es, void *ucontext); void md_executionstate_write(executionstate_t *es, void *ucontext); +#ifdef __cplusplus +} +#endif + #endif /* _EXECUTIONSTATE_H */ diff --git a/src/vm/jit/i386/codegen.c b/src/vm/jit/i386/codegen.c index 4f70c2a86..48a7758bb 100644 --- a/src/vm/jit/i386/codegen.c +++ b/src/vm/jit/i386/codegen.c @@ -62,7 +62,7 @@ #include "vm/jit/parse.h" #include "vm/jit/patcher-common.h" #include "vm/jit/reg.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/i386/emit.c b/src/vm/jit/i386/emit.c index 8d8940a34..2d63231c6 100644 --- a/src/vm/jit/i386/emit.c +++ b/src/vm/jit/i386/emit.c @@ -46,7 +46,7 @@ #include "vm/jit/emit-common.h" #include "vm/jit/jit.hpp" #include "vm/jit/patcher-common.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/trace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/ir/instruction.hpp b/src/vm/jit/ir/instruction.hpp index 7beb2e2d2..c9f3e3075 100644 --- a/src/vm/jit/ir/instruction.hpp +++ b/src/vm/jit/ir/instruction.hpp @@ -38,7 +38,7 @@ typedef struct insinfo_inline insinfo_inline; #include "vm/descriptor.h" #include "vm/jit/jit.hpp" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/ir/icmd.hpp" diff --git a/src/vm/jit/jit.hpp b/src/vm/jit/jit.hpp index fb1c7dab4..2ee4248bc 100644 --- a/src/vm/jit/jit.hpp +++ b/src/vm/jit/jit.hpp @@ -47,7 +47,7 @@ typedef struct exception_entry exception_entry; #include "vm/jit/codegen-common.h" #include "vm/jit/reg.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/stack.h" #include "vm/jit/stacktrace.hpp" diff --git a/src/vm/jit/m68k/codegen.c b/src/vm/jit/m68k/codegen.c index 62b9a1782..960d33fec 100644 --- a/src/vm/jit/m68k/codegen.c +++ b/src/vm/jit/m68k/codegen.c @@ -59,7 +59,7 @@ #include "vm/jit/abi.h" #include "vm/jit/parse.h" #include "vm/jit/reg.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/mips/codegen.c b/src/vm/jit/mips/codegen.c index 8ef9892d1..04aa48994 100644 --- a/src/vm/jit/mips/codegen.c +++ b/src/vm/jit/mips/codegen.c @@ -57,7 +57,7 @@ #include "vm/jit/linenumbertable.h" #include "vm/jit/patcher-common.h" #include "vm/jit/reg.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/trap.h" #if defined(ENABLE_LSRA) diff --git a/src/vm/jit/mips/emit.c b/src/vm/jit/mips/emit.c index a5d0ffd03..e1f2c2652 100644 --- a/src/vm/jit/mips/emit.c +++ b/src/vm/jit/mips/emit.c @@ -46,7 +46,7 @@ #include "vm/jit/emit-common.h" #include "vm/jit/jit.hpp" #include "vm/jit/patcher-common.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/powerpc/codegen.c b/src/vm/jit/powerpc/codegen.c index 8b22847c6..c22682d80 100644 --- a/src/vm/jit/powerpc/codegen.c +++ b/src/vm/jit/powerpc/codegen.c @@ -62,7 +62,7 @@ #include "vm/jit/parse.h" #include "vm/jit/patcher-common.h" #include "vm/jit/reg.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/powerpc/emit.c b/src/vm/jit/powerpc/emit.c index 21f03e35a..2ef0d7d1c 100644 --- a/src/vm/jit/powerpc/emit.c +++ b/src/vm/jit/powerpc/emit.c @@ -46,7 +46,7 @@ #include "vm/jit/dseg.h" #include "vm/jit/emit-common.h" #include "vm/jit/jit.hpp" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/trace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/powerpc64/codegen.c b/src/vm/jit/powerpc64/codegen.c index 211082c89..97606fb88 100644 --- a/src/vm/jit/powerpc64/codegen.c +++ b/src/vm/jit/powerpc64/codegen.c @@ -62,7 +62,7 @@ #include "vm/jit/parse.h" #include "vm/jit/patcher-common.h" #include "vm/jit/reg.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/replace.c b/src/vm/jit/replace.c deleted file mode 100644 index 8708e320c..000000000 --- a/src/vm/jit/replace.c +++ /dev/null @@ -1,3609 +0,0 @@ -/* src/vm/jit/replace.c - on-stack replacement of methods - - Copyright (C) 1996-2005, 2006, 2007, 2008 - CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO - - This file is part of CACAO. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. - -*/ - -#include "config.h" -#include "vm/types.h" - -#include -#include -#include - -#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.hpp" - -#include "toolbox/logging.h" - -#include "vm/classcache.h" -#include "vm/globals.hpp" -#include "vm/options.h" -#include "vm/string.hpp" - -#if defined(ENABLE_RT_TIMING) -# include "vm/rt-timing.h" -#endif - -#include "vm/jit/abi.h" -#include "vm/jit/asmpart.h" -#include "vm/jit/disass.h" -#include "vm/jit/executionstate.h" -#include "vm/jit/jit.hpp" -#include "vm/jit/methodheader.h" -#include "vm/jit/replace.h" -#include "vm/jit/show.h" -#include "vm/jit/stack.h" - - -#define REPLACE_PATCH_DYNAMIC_CALL -/*#define REPLACE_PATCH_ALL*/ - -#if defined(ENABLE_VMLOG) -#include -#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 **********************************/ - -/* XXX this should be in md-abi.h files, probably */ - -#if defined(HAS_4BYTE_STACKSLOT) -#define SIZE_OF_STACKSLOT 4 -#define STACK_SLOTS_PER_FLOAT 2 -typedef u4 stackslot_t; -#else -#define SIZE_OF_STACKSLOT 8 -#define STACK_SLOTS_PER_FLOAT 1 -typedef u8 stackslot_t; -#endif - - -/*** debugging ****************************************************************/ - -#if !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) -#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) -#endif - - -/*** statistics ***************************************************************/ - -#define REPLACE_STATISTICS - -#if defined(REPLACE_STATISTICS) - -static int stat_replacements = 0; -static int stat_frames = 0; -static int stat_recompile = 0; -static int stat_staticpatch = 0; -static int stat_unroll_inline = 0; -static int stat_unroll_call = 0; -static int stat_dist_frames[20] = { 0 }; -static int stat_dist_locals[20] = { 0 }; -static int stat_dist_locals_adr[10] = { 0 }; -static int stat_dist_locals_prim[10] = { 0 }; -static int stat_dist_locals_ret[10] = { 0 }; -static int stat_dist_locals_void[10] = { 0 }; -static int stat_dist_stack[10] = { 0 }; -static int stat_dist_stack_adr[10] = { 0 }; -static int stat_dist_stack_prim[10] = { 0 }; -static int stat_dist_stack_ret[10] = { 0 }; -static int stat_methods = 0; -static int stat_rploints = 0; -static int stat_regallocs = 0; -static int stat_dist_method_rplpoints[20] = { 0 }; - -#define REPLACE_COUNT(cnt) (cnt)++ -#define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0) -#define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc)) - -#define REPLACE_COUNT_DIST(array, val) \ - do { \ - int limit = (sizeof(array) / sizeof(int)) - 1; \ - if ((val) < (limit)) (array)[val]++; \ - else (array)[limit]++; \ - } while (0) - -static void replace_statistics_source_frame(sourceframe_t *frame); - -#else - -#define REPLACE_COUNT(cnt) -#define REPLACE_COUNT_IF(cnt, cond) -#define REPLACE_COUNT_INC(cnt, inc) -#define REPLACE_COUNT_DIST(array, val) - -#endif /* defined(REPLACE_STATISTICS) */ - - -/*** constants used internally ************************************************/ - -#define TOP_IS_NORMAL 0 -#define TOP_IS_ON_STACK 1 -#define TOP_IS_IN_ITMP1 2 -#define TOP_IS_VOID 3 - - -/******************************************************************************/ -/* PART I: Creating / freeing replacement points */ -/******************************************************************************/ - - -/* replace_create_replacement_point ******************************************** - - Create a replacement point. - - IN: - jd...............current jitdata - iinfo............inlining info for the current position - rp...............pre-allocated (uninitialized) rplpoint - type.............RPLPOINT_TYPE constant - iptr.............current instruction - *pra.............current rplalloc pointer - javalocals.......the javalocals at the current point - stackvars........the stack variables at the current point - stackdepth.......the stack depth at the current point - paramcount.......number of parameters at the start of stackvars - - OUT: - *rpa.............points to the next free rplalloc - -*******************************************************************************/ - -static void replace_create_replacement_point(jitdata *jd, - insinfo_inline *iinfo, - rplpoint *rp, - s4 type, - instruction *iptr, - rplalloc **pra, - s4 *javalocals, - s4 *stackvars, - s4 stackdepth, - s4 paramcount) -{ - rplalloc *ra; - s4 i; - varinfo *v; - s4 index; - - ra = *pra; - - REPLACE_COUNT(stat_rploints); - - rp->method = (iinfo) ? iinfo->method : jd->m; - rp->pc = NULL; /* set by codegen */ - rp->callsize = 0; /* set by codegen */ - rp->regalloc = ra; - rp->flags = 0; - rp->type = type; - rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT; - - /* XXX unify these two fields */ - rp->parent = (iinfo) ? iinfo->rp : NULL; - - /* store local allocation info of javalocals */ - - if (javalocals) { - for (i = 0; i < rp->method->maxlocals; ++i) { - index = javalocals[i]; - if (index == UNUSED) - continue; - - ra->index = i; - 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++; - } - } - - /* store allocation info of java stack vars */ - - for (i = 0; i < stackdepth; ++i) { - v = VAR(stackvars[i]); - ra->flags = v->flags & (INMEMORY); - ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK; - ra->type = v->type; - /* XXX how to handle locals on the stack containing returnAddresses? */ - if (v->type == TYPE_RET) { - assert(stackvars[i] >= jd->localcount); - ra->regoff = v->vv.retaddr->nr; - } - else - ra->regoff = v->vv.regoff; - ra++; - } - - /* total number of allocations */ - - rp->regalloccount = ra - rp->regalloc; - - *pra = ra; -} - - -/* replace_create_inline_start_replacement_point ******************************* - - Create an INLINE_START replacement point. - - IN: - jd...............current jitdata - rp...............pre-allocated (uninitialized) rplpoint - iptr.............current instruction - *pra.............current rplalloc pointer - javalocals.......the javalocals at the current point - - OUT: - *rpa.............points to the next free rplalloc - - RETURN VALUE: - the insinfo_inline * for the following inlined body - -*******************************************************************************/ - -static insinfo_inline * replace_create_inline_start_replacement_point( - jitdata *jd, - rplpoint *rp, - instruction *iptr, - rplalloc **pra, - s4 *javalocals) -{ - insinfo_inline *calleeinfo; - rplalloc *ra; - - calleeinfo = iptr->sx.s23.s3.inlineinfo; - - calleeinfo->rp = rp; - - replace_create_replacement_point(jd, calleeinfo->parent, rp, - RPLPOINT_TYPE_INLINE, iptr, pra, - javalocals, - calleeinfo->stackvars, calleeinfo->stackvarscount, - calleeinfo->paramcount); - - if (calleeinfo->synclocal != UNUSED) { - ra = (*pra)++; - ra->index = RPLALLOC_SYNC; - ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff; - ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY; - ra->type = TYPE_ADR; - - rp->regalloccount++; - } - - return calleeinfo; -} - - -/* replace_create_replacement_points ******************************************* - - Create the replacement points for the given code. - - IN: - jd...............current jitdata, must not have any replacement points - - OUT: - code->rplpoints.......set to the list of replacement points - code->rplpointcount...number of replacement points - code->regalloc........list of allocation info - code->regalloccount...total length of allocation info list - code->globalcount.....number of global allocations at the - start of code->regalloc - - RETURN VALUE: - true.............everything ok - false............an exception has been thrown - -*******************************************************************************/ - -#define CLEAR_javalocals(array, method) \ - do { \ - for (i=0; i<(method)->maxlocals; ++i) \ - (array)[i] = UNUSED; \ - } while (0) - -#define COPY_OR_CLEAR_javalocals(dest, array, method) \ - do { \ - if ((array) != NULL) \ - MCOPY((dest), (array), s4, (method)->maxlocals); \ - else \ - CLEAR_javalocals((dest), (method)); \ - } while (0) - -#define COUNT_javalocals(array, method, counter) \ - do { \ - for (i=0; i<(method)->maxlocals; ++i) \ - if ((array)[i] != UNUSED) \ - (counter)++; \ - } while (0) - -bool replace_create_replacement_points(jitdata *jd) -{ - codeinfo *code; - registerdata *rd; - basicblock *bptr; - int count; - methodinfo *m; - rplpoint *rplpoints; - rplpoint *rp; - int alloccount; - rplalloc *regalloc; - rplalloc *ra; - int i; - instruction *iptr; - instruction *iend; - s4 *javalocals; - s4 *jl; - methoddesc *md; - insinfo_inline *iinfo; - s4 startcount; - s4 firstcount; -#if defined(REPLACE_PATCH_DYNAMIC_CALL) - bool needentry; -#endif - - REPLACE_COUNT(stat_methods); - - /* get required compiler data */ - - code = jd->code; - rd = jd->rd; - - /* assert that we wont overwrite already allocated data */ - - assert(code); - assert(code->m); - assert(code->rplpoints == NULL); - assert(code->rplpointcount == 0); - assert(code->regalloc == NULL); - assert(code->regalloccount == 0); - assert(code->globalcount == 0); - - m = code->m; - - /* in instance methods, we may need a rplpoint at the method entry */ - -#if defined(REPLACE_PATCH_DYNAMIC_CALL) - if (!(m->flags & ACC_STATIC)) { - jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT; - needentry = true; - } - else { - needentry = false; - } -#endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */ - - /* iterate over the basic block list to find replacement points */ - - count = 0; - alloccount = 0; - - javalocals = DMNEW(s4, jd->maxlocals); - - for (bptr = jd->basicblocks; bptr; bptr = bptr->next) { - - /* skip dead code */ - - if (bptr->flags < BBFINISHED) - continue; - - /* get info about this block */ - - m = bptr->method; - iinfo = bptr->inlineinfo; - - /* initialize javalocals at the start of this block */ - - COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m); - - /* iterate over the instructions */ - - iptr = bptr->iinstr; - iend = iptr + bptr->icount; - startcount = count; - firstcount = count; - - 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: - case ICMD_INVOKEINTERFACE: - INSTRUCTION_GET_METHODDESC(iptr, md); - count++; - COUNT_javalocals(javalocals, m, alloccount); - alloccount += iptr->s1.argcount; - if (iinfo) - alloccount -= iinfo->throughcount; - break; - - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - case ICMD_DSTORE: - case ICMD_ASTORE: - stack_javalocals_store(iptr, javalocals); - break; - - case ICMD_IRETURN: - case ICMD_LRETURN: - case ICMD_FRETURN: - case ICMD_DRETURN: - case ICMD_ARETURN: - alloccount += 1; - /* FALLTHROUGH! */ - case ICMD_RETURN: - count++; - break; - - case ICMD_INLINE_START: - iinfo = iptr->sx.s23.s3.inlineinfo; - - count++; - COUNT_javalocals(javalocals, m, alloccount); - alloccount += iinfo->stackvarscount; - if (iinfo->synclocal != UNUSED) - alloccount++; - - m = iinfo->method; - /* javalocals may be set at next block start, or now */ - COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m); - break; - - case ICMD_INLINE_BODY: - assert(iinfo == iptr->sx.s23.s3.inlineinfo); - - jl = iinfo->javalocals_start; - if (jl == NULL) { - /* get the javalocals from the following block start */ - assert(bptr->next); - jl = bptr->next->javalocals; - } - count++; - COUNT_javalocals(jl, m, alloccount); - break; - - case ICMD_INLINE_END: - assert(iinfo == iptr->sx.s23.s3.inlineinfo || - iinfo == iptr->sx.s23.s3.inlineinfo->parent); - iinfo = iptr->sx.s23.s3.inlineinfo; - m = iinfo->outer; - if (iinfo->javalocals_end) - MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals); - iinfo = iinfo->parent; - break; - } - - if (iptr == bptr->iinstr) - firstcount = count; - } /* end instruction loop */ - - /* create replacement points at targets of backward branches */ - /* We only need the replacement point there, if there is no */ - /* replacement point inside the block. */ - - if (bptr->bitflags & BBFLAG_REPLACEMENT) { -#if defined(REPLACE_PATCH_DYNAMIC_CALL) - int test = (needentry && bptr == jd->basicblocks) ? firstcount : count; -#else - int test = count; -#endif - if (test > startcount) { - /* we don't need an extra rplpoint */ - bptr->bitflags &= ~BBFLAG_REPLACEMENT; - } - else { - count++; - alloccount += bptr->indepth; - if (bptr->inlineinfo) - alloccount -= bptr->inlineinfo->throughcount; - - COUNT_javalocals(bptr->javalocals, bptr->method, alloccount); - } - } - - } /* end basicblock loop */ - - /* if no points were found, there's nothing to do */ - - if (!count) - return true; - - /* allocate replacement point array and allocation array */ - - rplpoints = MNEW(rplpoint, count); - regalloc = MNEW(rplalloc, alloccount); - ra = regalloc; - - /* initialize replacement point structs */ - - rp = rplpoints; - - /* XXX try to share code with the counting loop! */ - - for (bptr = jd->basicblocks; bptr; bptr = bptr->next) { - /* skip dead code */ - - if (bptr->flags < BBFINISHED) - continue; - - /* get info about this block */ - - m = bptr->method; - iinfo = bptr->inlineinfo; - - /* initialize javalocals at the start of this block */ - - COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m); - - /* create replacement points at targets of backward branches */ - - if (bptr->bitflags & BBFLAG_REPLACEMENT) { - - i = (iinfo) ? iinfo->throughcount : 0; - 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 */ - - iptr = bptr->iinstr; - iend = iptr + bptr->icount; - - 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: - case ICMD_INVOKEINTERFACE: - INSTRUCTION_GET_METHODDESC(iptr, 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; - - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - case ICMD_DSTORE: - case ICMD_ASTORE: - stack_javalocals_store(iptr, javalocals); - break; - - case ICMD_IRETURN: - case ICMD_LRETURN: - case ICMD_FRETURN: - case ICMD_DRETURN: - case ICMD_ARETURN: - replace_create_replacement_point(jd, iinfo, rp++, - RPLPOINT_TYPE_RETURN, iptr, &ra, - NULL, &(iptr->s1.varindex), 1, 0); - break; - - case ICMD_RETURN: - replace_create_replacement_point(jd, iinfo, rp++, - RPLPOINT_TYPE_RETURN, iptr, &ra, - NULL, NULL, 0, 0); - break; - - case ICMD_INLINE_START: - iinfo = replace_create_inline_start_replacement_point( - jd, rp++, iptr, &ra, javalocals); - m = iinfo->method; - /* javalocals may be set at next block start, or now */ - COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m); - break; - - case ICMD_INLINE_BODY: - assert(iinfo == iptr->sx.s23.s3.inlineinfo); - - jl = iinfo->javalocals_start; - if (jl == NULL) { - /* get the javalocals from the following block start */ - assert(bptr->next); - jl = bptr->next->javalocals; - } - /* create a non-trappable rplpoint */ - replace_create_replacement_point(jd, iinfo, rp++, - RPLPOINT_TYPE_BODY, iptr, &ra, - jl, NULL, 0, 0); - rp[-1].flags |= RPLPOINT_FLAG_NOTRAP; - break; - - case ICMD_INLINE_END: - assert(iinfo == iptr->sx.s23.s3.inlineinfo || - iinfo == iptr->sx.s23.s3.inlineinfo->parent); - iinfo = iptr->sx.s23.s3.inlineinfo; - m = iinfo->outer; - if (iinfo->javalocals_end) - MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals); - iinfo = iinfo->parent; - break; - } - } /* end instruction loop */ - } /* end basicblock loop */ - - assert((rp - rplpoints) == count); - assert((ra - regalloc) == alloccount); - - /* store the data in the codeinfo */ - - code->rplpoints = rplpoints; - code->rplpointcount = count; - code->regalloc = regalloc; - code->regalloccount = alloccount; - 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; - - REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count); - REPLACE_COUNT_INC(stat_regallocs, alloccount); - - /* everything alright */ - - return true; -} - - -/* replace_free_replacement_points ********************************************* - - Free memory used by replacement points. - - IN: - code.............codeinfo whose replacement points should be freed. - -*******************************************************************************/ - -void replace_free_replacement_points(codeinfo *code) -{ - assert(code); - - if (code->rplpoints) - MFREE(code->rplpoints,rplpoint,code->rplpointcount); - - if (code->regalloc) - MFREE(code->regalloc,rplalloc,code->regalloccount); - - code->rplpoints = NULL; - code->rplpointcount = 0; - code->regalloc = NULL; - code->regalloccount = 0; - code->globalcount = 0; -} - - -/******************************************************************************/ -/* PART II: Activating / deactivating replacement points */ -/******************************************************************************/ - - -/* replace_activate_replacement_points ***************************************** - - Activate the replacement points of the given compilation unit. When this - function returns, the replacement points are "armed", so each thread - reaching one of the points will enter the replacement mechanism. - - IN: - code.............codeinfo of which replacement points should be - activated - mappable.........if true, only mappable replacement points are - activated - -*******************************************************************************/ - -void replace_activate_replacement_points(codeinfo *code, bool mappable) -{ - rplpoint *rp; - s4 i; - s4 count; - u1 *savedmcode; - - assert(code->savedmcode == NULL); - - /* count trappable replacement points */ - - count = 0; - i = code->rplpointcount; - rp = code->rplpoints; - for (; i--; rp++) { - if (rp->flags & RPLPOINT_FLAG_NOTRAP) - continue; - - if (mappable && (rp->type == RPLPOINT_TYPE_RETURN)) - continue; - - count++; - } - - /* allocate buffer for saved machine code */ - - savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE); - code->savedmcode = savedmcode; - savedmcode += count * REPLACEMENT_PATCH_SIZE; - - /* activate trappable replacement points */ - /* (in reverse order to handle overlapping points within basic blocks) */ - - i = code->rplpointcount; - rp = code->rplpoints + i; - while (rp--, i--) { - assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE)); - - if (rp->flags & RPLPOINT_FLAG_NOTRAP) - continue; - - if (mappable && (rp->type == RPLPOINT_TYPE_RETURN)) - continue; - - DOLOG( printf("activate replacement point:\n"); - replace_replacement_point_println(rp, 1); fflush(stdout); ); - - savedmcode -= REPLACEMENT_PATCH_SIZE; - -#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; - } - - assert(savedmcode == code->savedmcode); -} - - -/* replace_deactivate_replacement_points *************************************** - - Deactivate a replacement points in the given compilation unit. - When this function returns, the replacement points will be "un-armed", - that is a each thread reaching a point will just continue normally. - - IN: - code.............the compilation unit - -*******************************************************************************/ - -void replace_deactivate_replacement_points(codeinfo *code) -{ - rplpoint *rp; - s4 i; - 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; - - /* de-activate each trappable replacement point */ - - i = code->rplpointcount; - rp = code->rplpoints; - count = 0; - for (; i--; rp++) { - if (!(rp->flags & RPLPOINT_FLAG_ACTIVE)) - continue; - - count++; - - DOLOG( printf("deactivate replacement point:\n"); - replace_replacement_point_println(rp, 1); fflush(stdout); ); - -#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; - - savedmcode += REPLACEMENT_PATCH_SIZE; - } - - assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE); - - /* free saved machine code */ - - MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE); - code->savedmcode = NULL; -} - - -/******************************************************************************/ -/* PART III: The replacement mechanism */ -/******************************************************************************/ - - -/* replace_read_value ********************************************************** - - Read a value with the given allocation from the execution state. - - IN: - es...............execution state - ra...............allocation - javaval..........where to put the value - - OUT: - *javaval.........the value - -*******************************************************************************/ - -static void replace_read_value(executionstate_t *es, - rplalloc *ra, - 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->l = *(u8*)(es->sp + ra->regoff); - } - else { -#endif - javaval->p = *(ptrint*)(es->sp + ra->regoff); -#ifdef HAS_4BYTE_STACKSLOT - } -#endif - } - else { - /* allocated register */ - if (IS_FLT_DBL_TYPE(ra->type)) { - 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 { -#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]; - } - } -} - - -/* replace_write_value ********************************************************* - - Write a value to the given allocation in the execution state. - - IN: - es...............execution state - ra...............allocation - *javaval.........the value - -*******************************************************************************/ - -static void replace_write_value(executionstate_t *es, - rplalloc *ra, - 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*)(es->sp + ra->regoff) = javaval->l; - } - else { -#endif - *(ptrint*)(es->sp + ra->regoff) = javaval->p; -#ifdef HAS_4BYTE_STACKSLOT - } -#endif - } - else { - /* allocated register */ - 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_new_sourceframe ***************************************************** - - 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...............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 with the newly created source frame - added - -*******************************************************************************/ - -static s4 replace_normalize_type_map[] = { -/* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD, -/* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD, -/* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD, -/* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL, -/* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL, -/* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN, -/* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD -}; - - -static void replace_read_executionstate(rplpoint *rp, - executionstate_t *es, - sourcestate_t *ss, - bool topframe) -{ - methodinfo *m; - codeinfo *code; - int count; - int i; - rplalloc *ra; - sourceframe_t *frame; - int topslot; - stackslot_t *sp; - stackslot_t *basesp; - - code = code_find_codeinfo_for_pc(rp->pc); - m = rp->method; - topslot = TOP_IS_NORMAL; - - /* stack pointer */ - - sp = (stackslot_t *) es->sp; - - /* in some cases the top stack slot is passed in REG_ITMP1 */ - - if (rp->type == BBTYPE_EXH) { - topslot = TOP_IS_IN_ITMP1; - } - - /* calculate base stack pointer */ - - basesp = sp + code->stackframesize; - - /* create the source frame */ - - 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->fromrp = rp; - frame->fromcode = code; - - /* read local variables */ - - count = m->maxlocals; - frame->javalocalcount = count; - frame->javalocals = DMNEW(replace_val_t, count); - frame->javalocaltype = DMNEW(u1, count); - - /* mark values as undefined */ - for (i=0; ijavalocals[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;*/ -#if !defined(NDEBUG) - es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL; -#ifdef REG_PV - es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL; -#endif -#endif /* !defined(NDEBUG) */ - - /* read javalocals */ - - count = rp->regalloccount; - ra = rp->regalloc; - - while (count && (i = ra->index) >= 0) { - assert(i < m->maxlocals); - frame->javalocaltype[i] = ra->type; - if (ra->type == TYPE_RET) - frame->javalocals[i].i = ra->regoff; - else - replace_read_value(es, ra, frame->javalocals + i); - ra++; - count--; - } - - /* read instance, if this is the first rplpoint */ - -#if defined(REPLACE_PATCH_DYNAMIC_CALL) - if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) { -#if 1 - /* we are at the start of the method body, so if local 0 is set, */ - /* it is the instance. */ - if (frame->javalocaltype[0] == TYPE_ADR) - frame->instance = frame->javalocals[0]; -#else - rplalloc instra; - methoddesc *md; - - md = rp->method->parseddesc; - assert(md->params); - assert(md->paramcount >= 1); - instra.type = TYPE_ADR; - instra.regoff = md->params[0].regoff; - if (md->params[0].inmemory) { - instra.flags = INMEMORY; - instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT; - } - else { - instra.flags = 0; - } - 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(replace_val_t, count); - frame->javastacktype = DMNEW(u1, count); - -#if !defined(NDEBUG) - /* mark values as undefined */ - for (i=0; ijavastack[i].l = (u8) 0x00dead0000dead00ULL; - frame->javastacktype[i] = TYPE_VOID; - } -#endif /* !defined(NDEBUG) */ - - i = 0; - - /* the first stack slot is special in SBR and EXH blocks */ - - if (topslot == TOP_IS_ON_STACK) { - assert(count); - - assert(ra->index == RPLALLOC_STACK); - assert(ra->type == TYPE_ADR); - frame->javastack[i].p = sp[-1]; - frame->javastacktype[i] = TYPE_ADR; /* XXX RET */ - count--; - i++; - ra++; - } - else if (topslot == TOP_IS_IN_ITMP1) { - assert(count); - - assert(ra->index == RPLALLOC_STACK); - assert(ra->type == TYPE_ADR); - frame->javastack[i].p = es->intregs[REG_ITMP1]; - frame->javastacktype[i] = TYPE_ADR; /* XXX RET */ - count--; - i++; - ra++; - } - else if (topslot == TOP_IS_VOID) { - assert(count); - - assert(ra->index == RPLALLOC_STACK); - frame->javastack[i].l = 0; - frame->javastacktype[i] = TYPE_VOID; - count--; - i++; - ra++; - } - - /* read remaining stack slots */ - - for (; count--; ra++) { - if (ra->index == RPLALLOC_SYNC) { - assert(rp->type == RPLPOINT_TYPE_INLINE); - - /* only read synchronization slots when traversing an inline point */ - - if (!topframe) { - sourceframe_t *calleeframe = frame->down; - assert(calleeframe); - assert(calleeframe->syncslotcount == 0); - assert(calleeframe->syncslots == NULL); - - calleeframe->syncslotcount = 1; - calleeframe->syncslots = DMNEW(replace_val_t, 1); - replace_read_value(es,ra,calleeframe->syncslots); - } - - frame->javastackdepth--; - continue; - } - - assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM); - - /* do not read parameters of calls down the call chain */ - - if (!topframe && ra->index == RPLALLOC_PARAM) { - frame->javastackdepth--; - } - else { - if (ra->type == TYPE_RET) - frame->javastack[i].i = ra->regoff; - else - replace_read_value(es,ra,frame->javastack + i); - frame->javastacktype[i] = ra->type; - i++; - } - } -} - - -/* replace_write_executionstate ************************************************ - - 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 - 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 - -*******************************************************************************/ - -static void replace_write_executionstate(rplpoint *rp, - executionstate_t *es, - sourcestate_t *ss, - bool topframe) -{ - methodinfo *m; - codeinfo *code; - int count; - int i; - rplalloc *ra; - sourceframe_t *frame; - int topslot; - stackslot_t *sp; - stackslot_t *basesp; - - code = code_find_codeinfo_for_pc(rp->pc); - m = rp->method; - topslot = TOP_IS_NORMAL; - - /* pop a source frame */ - - frame = ss->frames; - assert(frame); - ss->frames = frame->down; - - /* calculate stack pointer */ - - sp = (stackslot_t *) es->sp; - - basesp = sp + code->stackframesize; - - /* in some cases the top stack slot is passed in REG_ITMP1 */ - - if (rp->type == BBTYPE_EXH) { - topslot = TOP_IS_IN_ITMP1; - } - - /* write javalocals */ - - ra = rp->regalloc; - count = rp->regalloccount; - - while (count && (i = ra->index) >= 0) { - assert(i < m->maxlocals); - assert(i < frame->javalocalcount); - assert(ra->type == frame->javalocaltype[i]); - if (ra->type == TYPE_RET) { - /* XXX assert that it matches this rplpoint */ - } - else - replace_write_value(es, ra, frame->javalocals + i); - count--; - ra++; - } - - /* write stack slots */ - - i = 0; - - /* the first stack slot is special in SBR and EXH blocks */ - - if (topslot == TOP_IS_ON_STACK) { - assert(count); - - assert(ra->index == RPLALLOC_STACK); - assert(i < frame->javastackdepth); - assert(frame->javastacktype[i] == TYPE_ADR); - sp[-1] = frame->javastack[i].p; - count--; - i++; - ra++; - } - else if (topslot == TOP_IS_IN_ITMP1) { - assert(count); - - assert(ra->index == RPLALLOC_STACK); - assert(i < frame->javastackdepth); - assert(frame->javastacktype[i] == TYPE_ADR); - es->intregs[REG_ITMP1] = frame->javastack[i].p; - count--; - i++; - ra++; - } - else if (topslot == TOP_IS_VOID) { - assert(count); - - assert(ra->index == RPLALLOC_STACK); - assert(i < frame->javastackdepth); - assert(frame->javastacktype[i] == TYPE_VOID); - count--; - i++; - ra++; - } - - /* write remaining stack slots */ - - for (; count--; ra++) { - if (ra->index == RPLALLOC_SYNC) { - assert(rp->type == RPLPOINT_TYPE_INLINE); - - /* only write synchronization slots when traversing an inline point */ - - if (!topframe) { - assert(frame->down); - assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */ - assert(frame->down->syncslots != NULL); - - replace_write_value(es,ra,frame->down->syncslots); - } - continue; - } - - assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM); - - /* do not write parameters of calls down the call chain */ - - 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); - assert(ra->type == frame->javastacktype[i]); - if (ra->type == TYPE_RET) { - /* XXX assert that it matches this rplpoint */ - } - else { - replace_write_value(es,ra,frame->javastack + i); - } - i++; - } - } - - /* set new pc */ - - es->pc = rp->pc; -} - - -/* 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. - - *** This function imitates the effects of the method epilog *** - *** and returning from the method call. *** - - IN: - es...............execution state - - OUT: - *es..............the execution state after popping the stack frame - NOTE: es->code and es->pv are NOT updated. - -*******************************************************************************/ - -void md_pop_stackframe(executionstate_t *es) -{ - u1 *ra; - s4 ra_align_off; - s4 reg; - s4 i; - stackslot_t *basesp; - stackslot_t *sp; - - assert(es->code); - - /* alignment offset of RA */ - - ra_align_off = 0; -#if defined(REPLACE_RA_BETWEEN_FRAMES) - if (es->code->stackframesize) - ra_align_off = SIZE_OF_STACKSLOT - SIZEOF_VOID_P; -#endif - - /* read the return address */ - -#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; - - /* restore return address, if part of frame */ - -#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 */ - - reg = INT_REG_CNT; - for (i=0; icode->savedintcount; ++i) { - while (nregdescint[--reg] != REG_SAV) - ; - es->intregs[reg] = *--basesp; - } - - /* restore saved flt registers */ - - /* XXX align? */ - reg = FLT_REG_CNT; - for (i=0; icode->savedfltcount; ++i) { - while (nregdescfloat[--reg] != REG_SAV) - ; - basesp -= STACK_SLOTS_PER_FLOAT; - es->fltregs[reg] = *(double*)basesp; - } - -#if defined(HAS_ADDRESS_REGISTER_FILE) - /* restore saved adr registers */ - - reg = ADR_REG_CNT; - for (i=0; icode->savedadrcount; ++i) { - while (nregdescadr[--reg] != REG_SAV) - ; - es->adrregs[reg] = *--basesp; - } -#endif - - /* adjust the stackpointer */ - - es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize; - -#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; iintregs[i] = (ptrint) 0x33dead3333dead33ULL; - for (i=0; ifltregs[i]) = 0x33dead3333dead33ULL; -# if defined(HAS_ADDRESS_REGISTER_FILE) - for (i=0; iadrregs[i] = (ptrint) 0x33dead3333dead33ULL; -# endif -#endif /* !defined(NDEBUG) */ -} - - -/* md_push_stackframe ********************************************************** - - 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: - 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. - -*******************************************************************************/ - -void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra) -{ - s4 reg; - s4 i; - stackslot_t *basesp; - stackslot_t *sp; - - assert(es); - assert(calleecode); - - /* write the return address */ - -#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 */ - - es->ra = (u1*) (ptrint) ra; - - /* 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 */ - - /* XXX may not invalidate linkage area used by native code! */ - -#if !defined(NDEBUG) && 0 - for (i=0; i< (basesp - sp) && i < 1; ++i) { - sp[i] = 0xdeaddeadU; - } -#endif - -#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 - - /* save the return address register */ - -#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 */ - -#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 */ - - /* save int registers */ - - reg = INT_REG_CNT; - for (i=0; isavedintcount; ++i) { - while (nregdescint[--reg] != REG_SAV) - ; - *--basesp = es->intregs[reg]; - - /* XXX may not clobber saved regs used by native code! */ -#if !defined(NDEBUG) && 0 - es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL; -#endif - } - - /* save flt registers */ - - /* XXX align? */ - reg = FLT_REG_CNT; - for (i=0; isavedfltcount; ++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; isavedadrcount; ++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; isyncslots[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.a) { - DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); ); - replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint); - return; - } - - /* get the vftbl */ - - obj = calleeframe->instance.a; - vftbl = obj->vftbl; - - assert(vftbl->clazz->vftbl == vftbl); - - DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->clazz); ); - - replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint); - } - else { - /* the call was statically bound */ - -#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 "); - } -} - - -/* replace_push_activation_record ********************************************** - - Push a stack frame onto the execution state. - - *** This function imitates the effects of a call and the *** - *** method prolog of the callee. *** - - IN: - es...............execution state - rpcall...........the replacement point at the call site - callerframe......source frame of the caller, or NULL for creating the - first frame - calleeframe......source frame of the callee, must have been mapped - - OUT: - *es..............the execution state after pushing the stack frame - -*******************************************************************************/ - -void replace_push_activation_record(executionstate_t *es, - rplpoint *rpcall, - sourceframe_t *callerframe, - sourceframe_t *calleeframe) -{ - s4 i; - s4 count; - stackslot_t *sp; - u1 *ra; - codeinfo *calleecode; - - assert(es); - assert(!rpcall || callerframe); - assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL); - assert(!rpcall || rpcall == callerframe->torp); - assert(calleeframe); - assert(!callerframe || calleeframe == callerframe->down); - - /* the compilation unit we are entering */ - - calleecode = calleeframe->tocode; - assert(calleecode); - - /* calculate the return address */ - - if (rpcall) - ra = rpcall->pc + rpcall->callsize; - else - ra = es->pc + 1 /* XXX this is ugly */; - - /* push the stackframe */ - - md_push_stackframe(es, calleecode, ra); - - /* we move into a new code unit, set code, PC, PV */ - - es->code = calleecode; - 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; imemuse + i] = calleeframe->syncslots[i].p; - } - - /* redirect future invocations */ - - if (callerframe && rpcall) { -#if defined(REPLACE_PATCH_ALL) - if (rpcall->type == callerframe->fromrp->type) -#else - if (rpcall == callerframe->fromrp) -#endif - replace_patch_future_calls(ra, callerframe, calleeframe); - } -} - - -/* replace_find_replacement_point ********************************************** - - Find the replacement point in the given code corresponding to the - position given in the source frame. - - IN: - code.............the codeinfo in which to search the rplpoint - frame............the source frame defining the position to look for - parent...........parent replacement point to match - - RETURN VALUE: - the replacement point - -*******************************************************************************/ - -rplpoint * replace_find_replacement_point(codeinfo *code, - sourceframe_t *frame, - rplpoint *parent) -{ - methodinfo *m; - rplpoint *rp; - s4 i; - s4 j; - s4 stacki; - rplalloc *ra; - - assert(code); - assert(frame); - - DOLOG( printf("searching replacement point for:\n"); - replace_source_frame_println(frame); ); - - m = frame->method; - - DOLOG( printf("code = %p\n", (void*)code); ); - - rp = code->rplpoints; - i = code->rplpointcount; - while (i--) { - if (rp->id == frame->id && rp->method == frame->method - && rp->parent == parent - && replace_normalize_type_map[rp->type] == frame->type) - { - /* check if returnAddresses match */ - /* XXX optimize: only do this if JSRs in method */ - DOLOG( printf("checking match for:"); - replace_replacement_point_println(rp, 1); fflush(stdout); ); - ra = rp->regalloc; - stacki = 0; - for (j = rp->regalloccount; j--; ++ra) { - if (ra->type == TYPE_RET) { - if (ra->index == RPLALLOC_STACK) { - assert(stacki < frame->javastackdepth); - 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].i != ra->regoff) - goto no_match; - } - } - } - - /* found */ - return rp; - } -no_match: - rp++; - } - -#if !defined(NDEBUG) - printf("candidate replacement points were:\n"); - rp = code->rplpoints; - i = code->rplpointcount; - for (; i--; ++rp) { - replace_replacement_point_println(rp, 1); - } -#endif - - vm_abort("no matching replacement point found"); - return NULL; /* NOT REACHED */ -} - - -/* replace_find_replacement_point_for_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 - pc...............the machine code PC - - RETURN VALUE: - the replacement point found, or - NULL if no replacement point was found - -*******************************************************************************/ - -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; irplpointcount; ++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) ? (((uintptr_t) sfi->sp) - ((uintptr_t) es->sp)) : 0; - assert(frame->nativeframesize >= 0); - - /* remember values of saved registers */ - - j = 0; - for (i=0; inativesavint[j++] = es->intregs[i]; - } - - j = 0; - for (i=0; inativesavflt[j++] = es->fltregs[i]; - } - -#if defined(HAS_ADDRESS_REGISTER_FILE) - j = 0; - for (i=0; inativesavadr[j++] = es->adrregs[i]; - } -#endif - - /* restore saved registers */ - -#if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE) - j = 0; - for (i=0; iintregs[i] = sfi->intregs[j++]; - } -#else - /* XXX we don't have them, yet, in the sfi, so clear them */ - - for (i=0; iintregs[i] = 0; - } -#endif - - /* XXX we don't have float registers in the sfi, so clear them */ - - for (i=0; ifltregs[i] = 0.0; - } - -#if defined(HAS_ADDRESS_REGISTER_FILE) -# if defined(ENABLE_GC_CACAO) - j = 0; - for (i=0; iadrregs[i] = sfi->adrregs[j++]; - } -# else - for (i=0; iadrregs[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 = (void*) (((uintptr_t) sfi->sp) + (*(s4 *) (((uintptr_t) 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 = (void*) (((uintptr_t) ((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 *) (((uintptr_t) 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; isfi->intregs[j++] = es->intregs[i]; - } -# else - for (i=0; isfi->adrregs[j++] = es->adrregs[i]; - } -# endif - - /* XXX leave float registers untouched here */ -#endif - - /* restore saved registers */ - - j = 0; - for (i=0; iintregs[i] = frame->nativesavint[j++]; - } - - j = 0; - for (i=0; ifltregs[i] = frame->nativesavflt[j++]; - } - -#if defined(HAS_ADDRESS_REGISTER_FILE) - j = 0; - for (i=0; iadrregs[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 ************************************************ - - Recover the source state from the given replacement point and execution - state. - - IN: - 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: - the source state - -*******************************************************************************/ - -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 - - /* create the source frame structure in dump memory */ - - ss = DNEW(sourcestate_t); - ss->frames = NULL; - - /* each iteration of the loop recovers one source frame */ - - depth = 0; - locked = false; - - while (rp || sfi) { - - 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 */ - - DOLOG( printf("recovering source state for%s:\n", - (ss->frames == NULL) ? " TOPFRAME" : ""); - replace_replacement_point_println(rp, 1); ); - - 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) { - /* this frame is in inlined code */ - - DOLOG( printf("INLINED!\n"); ); - - rp = rp->parent; - - assert(rp->type == RPLPOINT_TYPE_INLINE); - REPLACE_COUNT(stat_unroll_inline); - } - else { - /* 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("REACHED NATIVE CODE\n"); ); - - rp = NULL; - -#if !defined(ENABLE_GC_CACAO) - break; /* XXX remove to activate native frames */ -#endif - continue; - } - - /* 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"); - - DOLOG( printf("found replacement point.\n"); - replace_replacement_point_println(rp, 1); ); - - assert(rp->type == RPLPOINT_TYPE_CALL); - REPLACE_COUNT(stat_unroll_call); - } - } /* end loop over source frames */ - - REPLACE_COUNT_DIST(stat_dist_frames, depth); - - return ss; -} - - -/* replace_map_source_state **************************************************** - - Map each source frame in the given source state to a target replacement - point and compilation unit. If no valid code is available for a source - frame, it is (re)compiled. - - IN: - ss...............the source state - - OUT: - ss...............the source state, modified: The `torp` and `tocode` - fields of each source frame are set. - - RETURN VALUE: - true.............everything went ok - false............an exception has been thrown - -*******************************************************************************/ - -static bool replace_map_source_state(sourcestate_t *ss) -{ - sourceframe_t *frame; - codeinfo *code; - rplpoint *rp; - rplpoint *parent; /* parent of inlined rplpoint */ -#if defined(REPLACE_STATISTICS) - codeinfo *oldcode; -#endif - - parent = NULL; - code = NULL; - - /* iterate over the source frames from outermost to innermost */ - - for (frame = ss->frames; frame != NULL; frame = frame->down) { - - /* XXX skip native frames */ - - if (REPLACE_IS_NATIVE_FRAME(frame)) { - parent = NULL; - continue; - } - - /* map frames which are not already mapped */ - - if (frame->tocode) { - code = frame->tocode; - rp = frame->torp; - assert(rp); - } - else { - assert(frame->torp == NULL); - - if (parent == NULL) { - /* find code for this frame */ - -#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) - 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; - } - } - - return true; -} - - -/* 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. - - !!! CAUTION: This function rewrites the machine stack !!! - - THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA! - - IN: - ss...............the source state. Must have been mapped by - replace_map_source_state before. - es...............the base execution state on which to build - - OUT: - *es..............the new execution state - -*******************************************************************************/ - -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 (ss->frames) { - - 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); - - 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; - -#if defined(ENABLE_VMLOG) - vmlog_cacao_rerol_method(ss->frames->method); -#endif - - replace_write_executionstate(rp, es, ss, ss->frames->down == NULL); - - DOLOG( executionstate_println(es); ); - - if (rp->type == RPLPOINT_TYPE_CALL) { - parent = NULL; - } - else { - /* inlining */ - parent = rp; - } - } -} - - -/* 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! - - IN: - rp...............replacement point that has been reached - es...............execution state read by signal handler - -*******************************************************************************/ - -static void replace_me(rplpoint *rp, executionstate_t *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; - - origcode = es->code; - origrp = rp; - -#if defined(ENABLE_TLH) - /*printf("Replacing in %s/%s\n", rp->method->clazz->name->text, rp->method->name->text);*/ -#endif - - /*if (strcmp(rp->method->clazz->name->text, "antlr/AlternativeElement") == 0 && strcmp(rp->method->name->text, "getAutoGenType") ==0) opt_TraceReplacement = 2; else opt_TraceReplacement = 0;*/ - - 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_COUNT(stat_replacements); - - /* mark start of dump memory area */ - - DMARKER; - - /* Get the stackframeinfo for the current thread. */ - - sfi = threads_get_current_stackframeinfo(); - - /* recover source state */ - - ss = replace_recover_source_state(rp, sfi, es); - -#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO) - /* if there is a collection pending, we assume the replacement point should - suspend this thread */ - - if (gc_pending) { - - thread = THREADOBJECT; - - DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); ); - - /* map the sourcestate using the identity mapping */ - replace_map_source_state_identity(ss); - - /* since we enter the same method again, we turn off rps now */ - /* XXX michi: can we really do this? what if the rp was active before - we activated it for the gc? */ - replace_deactivate_replacement_points(origcode); - - /* remember executionstate and sourcestate for this thread */ - GC_EXECUTIONSTATE = es; - GC_SOURCESTATE = ss; - - /* really suspend this thread now (PC = 0) */ - threads_suspend_ack(NULL, NULL); - - DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); ); - - } else { -#endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/ - - /* map the source state */ - - if (!replace_map_source_state(ss)) - vm_abort("exception during method replacement"); - - DOLOG( replace_sourcestate_println(ss); ); - - DOLOG_SHORT( replace_sourcestate_println_short(ss); ); - -#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 - -#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO) - } -#endif - - /* build the new execution state */ - - replace_build_execution_state(ss, es); - -#if !defined(NDEBUG) - /* continue execution after patched machine code, if testing mode enabled */ - - if (opt_TestReplacement) - es->pc += REPLACEMENT_PATCH_SIZE; -#endif - - /* release dump area */ - - DRELEASE; -} - - -/* 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! - - 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; -#if defined(ENABLE_RT_TIMING) - struct timespec time_start, time_end; -#endif - - /* 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, (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN)); - - /* check if the replacement point belongs to given PC and is active */ - - if ((rp != NULL) && (rp->pc == pc) - && (rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))) { - - DOLOG( printf("valid replacement point\n"); ); - -#if !defined(NDEBUG) - executionstate_sanity_check(context); -#endif - - /* set codeinfo pointer in execution state */ - - es.code = code; - - /* read execution state from current context */ - - md_executionstate_read(&es, context); - - DOLOG( printf("REPLACEMENT READ: "); - executionstate_println(&es); ); - - /* 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 - - /* 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; -} - - -/******************************************************************************/ -/* 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; - - /* Get the stackframeinfo of this thread. */ - - assert(thread == THREADOBJECT); - - sfi = threads_get_current_stackframeinfo(); - - /* 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 */ - - /* we assume we are in a native (no replacement point)! */ - ss = replace_recover_source_state(NULL, sfi, es); - - /* 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 - -#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. */ -/******************************************************************************/ - - -/* statistics *****************************************************************/ - -#if defined(REPLACE_STATISTICS) -static void print_freq(FILE *file,int *array,int limit) -{ - int i; - int sum = 0; - int cum = 0; - for (i=0; i=%3d: %8d\n",limit,array[limit]); -} -#endif /* defined(REPLACE_STATISTICS) */ - - -#if defined(REPLACE_STATISTICS) - -#define REPLACE_PRINT_DIST(name, array) \ - printf(" " name " distribution:\n"); \ - print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1); - -void replace_print_statistics(void) -{ - printf("replacement statistics:\n"); - printf(" # of replacements: %d\n", stat_replacements); - printf(" # of frames: %d\n", stat_frames); - printf(" # of recompilations: %d\n", stat_recompile); - printf(" patched static calls:%d\n", stat_staticpatch); - printf(" unrolled inlines: %d\n", stat_unroll_inline); - printf(" unrolled calls: %d\n", stat_unroll_call); - REPLACE_PRINT_DIST("frame depth", stat_dist_frames); - REPLACE_PRINT_DIST("locals per frame", stat_dist_locals); - REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr); - REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim); - REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret); - REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void); - REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack); - REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr); - REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim); - REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret); - printf("\n"); - printf(" # of methods: %d\n", stat_methods); - printf(" # of replacement points: %d\n", stat_rploints); - printf(" # of regallocs: %d\n", stat_regallocs); - printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints); - printf(" per method: %f\n", (double)stat_regallocs / stat_methods); - REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints); - printf("\n"); - -} -#endif /* defined(REPLACE_STATISTICS) */ - - -#if defined(REPLACE_STATISTICS) -static void replace_statistics_source_frame(sourceframe_t *frame) -{ - int adr = 0; - int ret = 0; - int prim = 0; - int vd = 0; - int n = 0; - int i; - - for (i=0; ijavalocalcount; ++i) { - switch (frame->javalocaltype[i]) { - case TYPE_ADR: adr++; break; - case TYPE_RET: ret++; break; - case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break; - case TYPE_VOID: vd++; break; - default: assert(0); - } - n++; - } - REPLACE_COUNT_DIST(stat_dist_locals, n); - REPLACE_COUNT_DIST(stat_dist_locals_adr, adr); - REPLACE_COUNT_DIST(stat_dist_locals_void, vd); - REPLACE_COUNT_DIST(stat_dist_locals_ret, ret); - REPLACE_COUNT_DIST(stat_dist_locals_prim, prim); - adr = ret = prim = n = 0; - for (i=0; ijavastackdepth; ++i) { - switch (frame->javastacktype[i]) { - case TYPE_ADR: adr++; break; - case TYPE_RET: ret++; break; - case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break; - } - n++; - } - REPLACE_COUNT_DIST(stat_dist_stack, n); - REPLACE_COUNT_DIST(stat_dist_stack_adr, adr); - REPLACE_COUNT_DIST(stat_dist_stack_ret, ret); - REPLACE_COUNT_DIST(stat_dist_stack_prim, prim); -} -#endif /* defined(REPLACE_STATISTICS) */ - - -/* debugging helpers **********************************************************/ - -/* replace_replacement_point_println ******************************************* - - Print replacement point info. - - IN: - rp...............the replacement point to print - -*******************************************************************************/ - -#if !defined(NDEBUG) - -#define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?') - -static char *replace_type_str[] = { - "STD", - "EXH", - "SBR", - "CALL", - "INLINE", - "RETURN", - "BODY" -}; - -void replace_replacement_point_println(rplpoint *rp, int depth) -{ - int j; - int index; - - if (!rp) { - printf("(rplpoint *)NULL\n"); - return; - } - - for (j=0; jid, (void*)rp,rp->pc,rp->callsize, - 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); - for (j=0; jregalloccount); - - for (j=0; jregalloccount; ++j) { - if (j) - putchar(' '); - index = rp->regalloc[j].index; - switch (index) { - case RPLALLOC_STACK: printf("S"); break; - case RPLALLOC_PARAM: printf("P"); break; - case RPLALLOC_SYNC : printf("Y"); break; - default: printf("%d", index); - } - printf(":%1c:", TYPECHAR(rp->regalloc[j].type)); - if (rp->regalloc[j].type == TYPE_RET) { - printf("ret(L%03d)", rp->regalloc[j].regoff); - } - else { - show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff); - } - } - - printf("]\n"); - for (j=0; jmethod); - - printf("\n"); -} -#endif /* !defined(NDEBUG) */ - - -/* replace_show_replacement_points ********************************************* - - Print replacement point info. - - IN: - code.............codeinfo whose replacement points should be printed. - -*******************************************************************************/ - -#if !defined(NDEBUG) -void replace_show_replacement_points(codeinfo *code) -{ - int i; - int depth; - rplpoint *rp; - rplpoint *parent; - - if (!code) { - printf("(codeinfo *)NULL\n"); - return; - } - - printf("\treplacement points: %d\n",code->rplpointcount); - - 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"); - - for (i=0; irplpointcount; ++i) { - rp = code->rplpoints + i; - - depth = 1; - parent = rp->parent; - while (parent) { - depth++; - parent = parent->parent; - } - replace_replacement_point_println(rp, depth); - } -} -#endif - - -#if !defined(NDEBUG) -static void java_value_print(s4 type, replace_val_t value) -{ - java_object_t *obj; - utf *u; - - printf("%016llx",(unsigned long long) value.l); - - if (type < 0 || type > TYPE_RET) - printf(" ", type); - else - printf(" %s", show_jit_type_names[type]); - - if (type == TYPE_ADR && value.a != NULL) { - obj = value.a; - putchar(' '); - utf_display_printable_ascii_classname(obj->vftbl->clazz->name); - - if (obj->vftbl->clazz == class_java_lang_String) { - printf(" \""); - u = javastring_toutf(obj, false); - utf_display_printable_ascii(u); - printf("\""); - } - } - 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,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; inativesavint[j++]); - } - - j = 0; - for (i=0; inativesavflt[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.a) { - printf("\tinstance: "); - java_value_print(TYPE_ADR, frame->instance); - printf("\n"); - } - - if (frame->javalocalcount) { - printf("\tlocals (%d):\n",frame->javalocalcount); - for (i=0; ijavalocalcount; ++i) { - t = frame->javalocaltype[i]; - if (t == TYPE_VOID) { - printf("\tlocal[ %2d] = void\n",i); - } - else { - printf("\tlocal[%c%2d] = ",TYPECHAR(t),i); - java_value_print(t, frame->javalocals[i]); - printf("\n"); - } - } - printf("\n"); - } - - if (frame->javastackdepth) { - printf("\tstack (depth %d):\n",frame->javastackdepth); - for (i=0; ijavastackdepth; ++i) { - t = frame->javastacktype[i]; - if (t == TYPE_VOID) { - printf("\tstack[%2d] = void", i); - } - else { - printf("\tstack[%2d] = ",i); - java_value_print(frame->javastacktype[i], frame->javastack[i]); - printf("\n"); - } - } - printf("\n"); - } - - if (frame->syncslotcount) { - printf("\tsynchronization slots (%d):\n",frame->syncslotcount); - for (i=0; isyncslotcount; ++i) { - printf("\tslot[%2d] = ",i); -#ifdef HAS_4BYTE_STACKSLOT - printf("%08lx\n",(unsigned long) frame->syncslots[i].p); -#else - printf("%016llx\n",(unsigned long long) frame->syncslots[i].p); -#endif - } - printf("\n"); - } - - if (frame->fromcode) { - printf("\tfrom %p ", (void*)frame->fromcode); - method_println(frame->fromcode->m); - } - if (frame->tocode) { - printf("\tto %p ", (void*)frame->tocode); - method_println(frame->tocode->m); - } - - if (frame->fromrp) { - printf("\tfrom replacement point:\n"); - replace_replacement_point_println(frame->fromrp, 2); - } - if (frame->torp) { - printf("\tto replacement point:\n"); - replace_replacement_point_println(frame->torp, 2); - } - - printf("\n"); -} -#endif /* !defined(NDEBUG) */ - - -/* replace_sourcestate_println ************************************************* - - Print source state - - IN: - ss...............the source state to print - -*******************************************************************************/ - -#if !defined(NDEBUG) -void replace_sourcestate_println(sourcestate_t *ss) -{ - int i; - sourceframe_t *frame; - - if (!ss) { - printf("(sourcestate_t *)NULL\n"); - return; - } - - printf("sourcestate_t:\n"); - - for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) { - printf(" frame %d:\n", i); - replace_source_frame_println(frame); - } -} -#endif - - -/* replace_sourcestate_println_short ******************************************* - - Print a compact representation of the given source state. - - IN: - ss...............the source state to print - -*******************************************************************************/ - -#if !defined(NDEBUG) -void replace_sourcestate_println_short(sourcestate_t *ss) -{ - sourceframe_t *frame; - - 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) ? '=' : '+'); - } - - printf("%s", replace_type_str[frame->fromrp->type]); - - if (frame->torp && frame->torp->type != frame->fromrp->type) - printf("->%s", replace_type_str[frame->torp->type]); - - if (frame->tocode != frame->fromcode) - printf(" (%p->%p/%d) ", - (void*) frame->fromcode, (void*) frame->tocode, - frame->fromrp->id); - else - printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id); - - method_println(frame->method); - } -} -#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 - * Emacs will automagically detect them. - * --------------------------------------------------------------------- - * Local variables: - * mode: c - * indent-tabs-mode: t - * c-basic-offset: 4 - * tab-width: 4 - * End: - * vim:noexpandtab:sw=4:ts=4: - */ diff --git a/src/vm/jit/replace.cpp b/src/vm/jit/replace.cpp new file mode 100644 index 000000000..a4ea93b19 --- /dev/null +++ b/src/vm/jit/replace.cpp @@ -0,0 +1,3609 @@ +/* src/vm/jit/replace.cpp - on-stack replacement of methods + + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + +*/ + + +#include "config.h" +#include "vm/types.h" + +#include +#include +#include + +#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.hpp" + +#include "toolbox/logging.h" + +#include "vm/classcache.h" +#include "vm/globals.hpp" +#include "vm/options.h" +#include "vm/string.hpp" + +#if defined(ENABLE_RT_TIMING) +# include "vm/rt-timing.h" +#endif + +#include "vm/jit/abi.h" +#include "vm/jit/asmpart.h" +#include "vm/jit/disass.h" +#include "vm/jit/executionstate.h" +#include "vm/jit/jit.hpp" +#include "vm/jit/methodheader.h" +#include "vm/jit/replace.hpp" +#include "vm/jit/show.h" +#include "vm/jit/stack.h" + + +#define REPLACE_PATCH_DYNAMIC_CALL +/*#define REPLACE_PATCH_ALL*/ + +#if defined(ENABLE_VMLOG) +#include +#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 **********************************/ + +/* XXX this should be in md-abi.h files, probably */ + +#if defined(HAS_4BYTE_STACKSLOT) +#define SIZE_OF_STACKSLOT 4 +#define STACK_SLOTS_PER_FLOAT 2 +typedef u4 stackslot_t; +#else +#define SIZE_OF_STACKSLOT 8 +#define STACK_SLOTS_PER_FLOAT 1 +typedef u8 stackslot_t; +#endif + + +/*** debugging ****************************************************************/ + +#if !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) +#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) +#endif + + +/*** statistics ***************************************************************/ + +#define REPLACE_STATISTICS + +#if defined(REPLACE_STATISTICS) + +static int stat_replacements = 0; +static int stat_frames = 0; +static int stat_recompile = 0; +static int stat_staticpatch = 0; +static int stat_unroll_inline = 0; +static int stat_unroll_call = 0; +static int stat_dist_frames[20] = { 0 }; +static int stat_dist_locals[20] = { 0 }; +static int stat_dist_locals_adr[10] = { 0 }; +static int stat_dist_locals_prim[10] = { 0 }; +static int stat_dist_locals_ret[10] = { 0 }; +static int stat_dist_locals_void[10] = { 0 }; +static int stat_dist_stack[10] = { 0 }; +static int stat_dist_stack_adr[10] = { 0 }; +static int stat_dist_stack_prim[10] = { 0 }; +static int stat_dist_stack_ret[10] = { 0 }; +static int stat_methods = 0; +static int stat_rploints = 0; +static int stat_regallocs = 0; +static int stat_dist_method_rplpoints[20] = { 0 }; + +#define REPLACE_COUNT(cnt) (cnt)++ +#define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0) +#define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc)) + +#define REPLACE_COUNT_DIST(array, val) \ + do { \ + int limit = (sizeof(array) / sizeof(int)) - 1; \ + if ((val) < (limit)) (array)[val]++; \ + else (array)[limit]++; \ + } while (0) + +static void replace_statistics_source_frame(sourceframe_t *frame); + +#else + +#define REPLACE_COUNT(cnt) +#define REPLACE_COUNT_IF(cnt, cond) +#define REPLACE_COUNT_INC(cnt, inc) +#define REPLACE_COUNT_DIST(array, val) + +#endif /* defined(REPLACE_STATISTICS) */ + + +/*** constants used internally ************************************************/ + +#define TOP_IS_NORMAL 0 +#define TOP_IS_ON_STACK 1 +#define TOP_IS_IN_ITMP1 2 +#define TOP_IS_VOID 3 + + +/******************************************************************************/ +/* PART I: Creating / freeing replacement points */ +/******************************************************************************/ + + +/* replace_create_replacement_point ******************************************** + + Create a replacement point. + + IN: + jd...............current jitdata + iinfo............inlining info for the current position + rp...............pre-allocated (uninitialized) rplpoint + type.............RPLPOINT_TYPE constant + iptr.............current instruction + *pra.............current rplalloc pointer + javalocals.......the javalocals at the current point + stackvars........the stack variables at the current point + stackdepth.......the stack depth at the current point + paramcount.......number of parameters at the start of stackvars + + OUT: + *rpa.............points to the next free rplalloc + +*******************************************************************************/ + +static void replace_create_replacement_point(jitdata *jd, + insinfo_inline *iinfo, + rplpoint *rp, + s4 type, + instruction *iptr, + rplalloc **pra, + s4 *javalocals, + s4 *stackvars, + s4 stackdepth, + s4 paramcount) +{ + rplalloc *ra; + s4 i; + varinfo *v; + s4 index; + + ra = *pra; + + REPLACE_COUNT(stat_rploints); + + rp->method = (iinfo) ? iinfo->method : jd->m; + rp->pc = NULL; /* set by codegen */ + rp->callsize = 0; /* set by codegen */ + rp->regalloc = ra; + rp->flags = 0; + rp->type = type; + rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT; + + /* XXX unify these two fields */ + rp->parent = (iinfo) ? iinfo->rp : NULL; + + /* store local allocation info of javalocals */ + + if (javalocals) { + for (i = 0; i < rp->method->maxlocals; ++i) { + index = javalocals[i]; + if (index == UNUSED) + continue; + + ra->index = i; + 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++; + } + } + + /* store allocation info of java stack vars */ + + for (i = 0; i < stackdepth; ++i) { + v = VAR(stackvars[i]); + ra->flags = v->flags & (INMEMORY); + ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK; + ra->type = v->type; + /* XXX how to handle locals on the stack containing returnAddresses? */ + if (v->type == TYPE_RET) { + assert(stackvars[i] >= jd->localcount); + ra->regoff = v->vv.retaddr->nr; + } + else + ra->regoff = v->vv.regoff; + ra++; + } + + /* total number of allocations */ + + rp->regalloccount = ra - rp->regalloc; + + *pra = ra; +} + + +/* replace_create_inline_start_replacement_point ******************************* + + Create an INLINE_START replacement point. + + IN: + jd...............current jitdata + rp...............pre-allocated (uninitialized) rplpoint + iptr.............current instruction + *pra.............current rplalloc pointer + javalocals.......the javalocals at the current point + + OUT: + *rpa.............points to the next free rplalloc + + RETURN VALUE: + the insinfo_inline * for the following inlined body + +*******************************************************************************/ + +static insinfo_inline * replace_create_inline_start_replacement_point( + jitdata *jd, + rplpoint *rp, + instruction *iptr, + rplalloc **pra, + s4 *javalocals) +{ + insinfo_inline *calleeinfo; + rplalloc *ra; + + calleeinfo = iptr->sx.s23.s3.inlineinfo; + + calleeinfo->rp = rp; + + replace_create_replacement_point(jd, calleeinfo->parent, rp, + RPLPOINT_TYPE_INLINE, iptr, pra, + javalocals, + calleeinfo->stackvars, calleeinfo->stackvarscount, + calleeinfo->paramcount); + + if (calleeinfo->synclocal != UNUSED) { + ra = (*pra)++; + ra->index = RPLALLOC_SYNC; + ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff; + ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY; + ra->type = TYPE_ADR; + + rp->regalloccount++; + } + + return calleeinfo; +} + + +/* replace_create_replacement_points ******************************************* + + Create the replacement points for the given code. + + IN: + jd...............current jitdata, must not have any replacement points + + OUT: + code->rplpoints.......set to the list of replacement points + code->rplpointcount...number of replacement points + code->regalloc........list of allocation info + code->regalloccount...total length of allocation info list + code->globalcount.....number of global allocations at the + start of code->regalloc + + RETURN VALUE: + true.............everything ok + false............an exception has been thrown + +*******************************************************************************/ + +#define CLEAR_javalocals(array, method) \ + do { \ + for (i=0; i<(method)->maxlocals; ++i) \ + (array)[i] = UNUSED; \ + } while (0) + +#define COPY_OR_CLEAR_javalocals(dest, array, method) \ + do { \ + if ((array) != NULL) \ + MCOPY((dest), (array), s4, (method)->maxlocals); \ + else \ + CLEAR_javalocals((dest), (method)); \ + } while (0) + +#define COUNT_javalocals(array, method, counter) \ + do { \ + for (i=0; i<(method)->maxlocals; ++i) \ + if ((array)[i] != UNUSED) \ + (counter)++; \ + } while (0) + +bool replace_create_replacement_points(jitdata *jd) +{ + codeinfo *code; + registerdata *rd; + basicblock *bptr; + int count; + methodinfo *m; + rplpoint *rplpoints; + rplpoint *rp; + int alloccount; + rplalloc *regalloc; + rplalloc *ra; + int i; + instruction *iptr; + instruction *iend; + s4 *javalocals; + s4 *jl; + methoddesc *md; + insinfo_inline *iinfo; + s4 startcount; + s4 firstcount; +#if defined(REPLACE_PATCH_DYNAMIC_CALL) + bool needentry; +#endif + + REPLACE_COUNT(stat_methods); + + /* get required compiler data */ + + code = jd->code; + rd = jd->rd; + + /* assert that we wont overwrite already allocated data */ + + assert(code); + assert(code->m); + assert(code->rplpoints == NULL); + assert(code->rplpointcount == 0); + assert(code->regalloc == NULL); + assert(code->regalloccount == 0); + assert(code->globalcount == 0); + + m = code->m; + + /* in instance methods, we may need a rplpoint at the method entry */ + +#if defined(REPLACE_PATCH_DYNAMIC_CALL) + if (!(m->flags & ACC_STATIC)) { + jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT; + needentry = true; + } + else { + needentry = false; + } +#endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */ + + /* iterate over the basic block list to find replacement points */ + + count = 0; + alloccount = 0; + + javalocals = DMNEW(s4, jd->maxlocals); + + for (bptr = jd->basicblocks; bptr; bptr = bptr->next) { + + /* skip dead code */ + + if (bptr->flags < BBFINISHED) + continue; + + /* get info about this block */ + + m = bptr->method; + iinfo = bptr->inlineinfo; + + /* initialize javalocals at the start of this block */ + + COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m); + + /* iterate over the instructions */ + + iptr = bptr->iinstr; + iend = iptr + bptr->icount; + startcount = count; + firstcount = count; + + 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: + case ICMD_INVOKEINTERFACE: + INSTRUCTION_GET_METHODDESC(iptr, md); + count++; + COUNT_javalocals(javalocals, m, alloccount); + alloccount += iptr->s1.argcount; + if (iinfo) + alloccount -= iinfo->throughcount; + break; + + case ICMD_ISTORE: + case ICMD_LSTORE: + case ICMD_FSTORE: + case ICMD_DSTORE: + case ICMD_ASTORE: + stack_javalocals_store(iptr, javalocals); + break; + + case ICMD_IRETURN: + case ICMD_LRETURN: + case ICMD_FRETURN: + case ICMD_DRETURN: + case ICMD_ARETURN: + alloccount += 1; + /* FALLTHROUGH! */ + case ICMD_RETURN: + count++; + break; + + case ICMD_INLINE_START: + iinfo = iptr->sx.s23.s3.inlineinfo; + + count++; + COUNT_javalocals(javalocals, m, alloccount); + alloccount += iinfo->stackvarscount; + if (iinfo->synclocal != UNUSED) + alloccount++; + + m = iinfo->method; + /* javalocals may be set at next block start, or now */ + COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m); + break; + + case ICMD_INLINE_BODY: + assert(iinfo == iptr->sx.s23.s3.inlineinfo); + + jl = iinfo->javalocals_start; + if (jl == NULL) { + /* get the javalocals from the following block start */ + assert(bptr->next); + jl = bptr->next->javalocals; + } + count++; + COUNT_javalocals(jl, m, alloccount); + break; + + case ICMD_INLINE_END: + assert(iinfo == iptr->sx.s23.s3.inlineinfo || + iinfo == iptr->sx.s23.s3.inlineinfo->parent); + iinfo = iptr->sx.s23.s3.inlineinfo; + m = iinfo->outer; + if (iinfo->javalocals_end) + MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals); + iinfo = iinfo->parent; + break; + } + + if (iptr == bptr->iinstr) + firstcount = count; + } /* end instruction loop */ + + /* create replacement points at targets of backward branches */ + /* We only need the replacement point there, if there is no */ + /* replacement point inside the block. */ + + if (bptr->bitflags & BBFLAG_REPLACEMENT) { +#if defined(REPLACE_PATCH_DYNAMIC_CALL) + int test = (needentry && bptr == jd->basicblocks) ? firstcount : count; +#else + int test = count; +#endif + if (test > startcount) { + /* we don't need an extra rplpoint */ + bptr->bitflags &= ~BBFLAG_REPLACEMENT; + } + else { + count++; + alloccount += bptr->indepth; + if (bptr->inlineinfo) + alloccount -= bptr->inlineinfo->throughcount; + + COUNT_javalocals(bptr->javalocals, bptr->method, alloccount); + } + } + + } /* end basicblock loop */ + + /* if no points were found, there's nothing to do */ + + if (!count) + return true; + + /* allocate replacement point array and allocation array */ + + rplpoints = MNEW(rplpoint, count); + regalloc = MNEW(rplalloc, alloccount); + ra = regalloc; + + /* initialize replacement point structs */ + + rp = rplpoints; + + /* XXX try to share code with the counting loop! */ + + for (bptr = jd->basicblocks; bptr; bptr = bptr->next) { + /* skip dead code */ + + if (bptr->flags < BBFINISHED) + continue; + + /* get info about this block */ + + m = bptr->method; + iinfo = bptr->inlineinfo; + + /* initialize javalocals at the start of this block */ + + COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m); + + /* create replacement points at targets of backward branches */ + + if (bptr->bitflags & BBFLAG_REPLACEMENT) { + + i = (iinfo) ? iinfo->throughcount : 0; + 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 */ + + iptr = bptr->iinstr; + iend = iptr + bptr->icount; + + 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: + case ICMD_INVOKEINTERFACE: + INSTRUCTION_GET_METHODDESC(iptr, 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; + + case ICMD_ISTORE: + case ICMD_LSTORE: + case ICMD_FSTORE: + case ICMD_DSTORE: + case ICMD_ASTORE: + stack_javalocals_store(iptr, javalocals); + break; + + case ICMD_IRETURN: + case ICMD_LRETURN: + case ICMD_FRETURN: + case ICMD_DRETURN: + case ICMD_ARETURN: + replace_create_replacement_point(jd, iinfo, rp++, + RPLPOINT_TYPE_RETURN, iptr, &ra, + NULL, &(iptr->s1.varindex), 1, 0); + break; + + case ICMD_RETURN: + replace_create_replacement_point(jd, iinfo, rp++, + RPLPOINT_TYPE_RETURN, iptr, &ra, + NULL, NULL, 0, 0); + break; + + case ICMD_INLINE_START: + iinfo = replace_create_inline_start_replacement_point( + jd, rp++, iptr, &ra, javalocals); + m = iinfo->method; + /* javalocals may be set at next block start, or now */ + COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m); + break; + + case ICMD_INLINE_BODY: + assert(iinfo == iptr->sx.s23.s3.inlineinfo); + + jl = iinfo->javalocals_start; + if (jl == NULL) { + /* get the javalocals from the following block start */ + assert(bptr->next); + jl = bptr->next->javalocals; + } + /* create a non-trappable rplpoint */ + replace_create_replacement_point(jd, iinfo, rp++, + RPLPOINT_TYPE_BODY, iptr, &ra, + jl, NULL, 0, 0); + rp[-1].flags |= RPLPOINT_FLAG_NOTRAP; + break; + + case ICMD_INLINE_END: + assert(iinfo == iptr->sx.s23.s3.inlineinfo || + iinfo == iptr->sx.s23.s3.inlineinfo->parent); + iinfo = iptr->sx.s23.s3.inlineinfo; + m = iinfo->outer; + if (iinfo->javalocals_end) + MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals); + iinfo = iinfo->parent; + break; + } + } /* end instruction loop */ + } /* end basicblock loop */ + + assert((rp - rplpoints) == count); + assert((ra - regalloc) == alloccount); + + /* store the data in the codeinfo */ + + code->rplpoints = rplpoints; + code->rplpointcount = count; + code->regalloc = regalloc; + code->regalloccount = alloccount; + 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; + + REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count); + REPLACE_COUNT_INC(stat_regallocs, alloccount); + + /* everything alright */ + + return true; +} + + +/* replace_free_replacement_points ********************************************* + + Free memory used by replacement points. + + IN: + code.............codeinfo whose replacement points should be freed. + +*******************************************************************************/ + +void replace_free_replacement_points(codeinfo *code) +{ + assert(code); + + if (code->rplpoints) + MFREE(code->rplpoints,rplpoint,code->rplpointcount); + + if (code->regalloc) + MFREE(code->regalloc,rplalloc,code->regalloccount); + + code->rplpoints = NULL; + code->rplpointcount = 0; + code->regalloc = NULL; + code->regalloccount = 0; + code->globalcount = 0; +} + + +/******************************************************************************/ +/* PART II: Activating / deactivating replacement points */ +/******************************************************************************/ + + +/* replace_activate_replacement_points ***************************************** + + Activate the replacement points of the given compilation unit. When this + function returns, the replacement points are "armed", so each thread + reaching one of the points will enter the replacement mechanism. + + IN: + code.............codeinfo of which replacement points should be + activated + mappable.........if true, only mappable replacement points are + activated + +*******************************************************************************/ + +void replace_activate_replacement_points(codeinfo *code, bool mappable) +{ + rplpoint *rp; + s4 i; + s4 count; + u1 *savedmcode; + + assert(code->savedmcode == NULL); + + /* count trappable replacement points */ + + count = 0; + i = code->rplpointcount; + rp = code->rplpoints; + for (; i--; rp++) { + if (rp->flags & RPLPOINT_FLAG_NOTRAP) + continue; + + if (mappable && (rp->type == RPLPOINT_TYPE_RETURN)) + continue; + + count++; + } + + /* allocate buffer for saved machine code */ + + savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE); + code->savedmcode = savedmcode; + savedmcode += count * REPLACEMENT_PATCH_SIZE; + + /* activate trappable replacement points */ + /* (in reverse order to handle overlapping points within basic blocks) */ + + i = code->rplpointcount; + rp = code->rplpoints + i; + while (rp--, i--) { + assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE)); + + if (rp->flags & RPLPOINT_FLAG_NOTRAP) + continue; + + if (mappable && (rp->type == RPLPOINT_TYPE_RETURN)) + continue; + + DOLOG( printf("activate replacement point:\n"); + replace_replacement_point_println(rp, 1); fflush(stdout); ); + + savedmcode -= REPLACEMENT_PATCH_SIZE; + +#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; + } + + assert(savedmcode == code->savedmcode); +} + + +/* replace_deactivate_replacement_points *************************************** + + Deactivate a replacement points in the given compilation unit. + When this function returns, the replacement points will be "un-armed", + that is a each thread reaching a point will just continue normally. + + IN: + code.............the compilation unit + +*******************************************************************************/ + +void replace_deactivate_replacement_points(codeinfo *code) +{ + rplpoint *rp; + s4 i; + 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; + + /* de-activate each trappable replacement point */ + + i = code->rplpointcount; + rp = code->rplpoints; + count = 0; + for (; i--; rp++) { + if (!(rp->flags & RPLPOINT_FLAG_ACTIVE)) + continue; + + count++; + + DOLOG( printf("deactivate replacement point:\n"); + replace_replacement_point_println(rp, 1); fflush(stdout); ); + +#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; + + savedmcode += REPLACEMENT_PATCH_SIZE; + } + + assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE); + + /* free saved machine code */ + + MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE); + code->savedmcode = NULL; +} + + +/******************************************************************************/ +/* PART III: The replacement mechanism */ +/******************************************************************************/ + + +/* replace_read_value ********************************************************** + + Read a value with the given allocation from the execution state. + + IN: + es...............execution state + ra...............allocation + javaval..........where to put the value + + OUT: + *javaval.........the value + +*******************************************************************************/ + +static void replace_read_value(executionstate_t *es, + rplalloc *ra, + 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->l = *(u8*)(es->sp + ra->regoff); + } + else { +#endif + javaval->p = *(ptrint*)(es->sp + ra->regoff); +#ifdef HAS_4BYTE_STACKSLOT + } +#endif + } + else { + /* allocated register */ + if (IS_FLT_DBL_TYPE(ra->type)) { + 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 { +#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]; + } + } +} + + +/* replace_write_value ********************************************************* + + Write a value to the given allocation in the execution state. + + IN: + es...............execution state + ra...............allocation + *javaval.........the value + +*******************************************************************************/ + +static void replace_write_value(executionstate_t *es, + rplalloc *ra, + 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*)(es->sp + ra->regoff) = javaval->l; + } + else { +#endif + *(ptrint*)(es->sp + ra->regoff) = javaval->p; +#ifdef HAS_4BYTE_STACKSLOT + } +#endif + } + else { + /* allocated register */ + 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_new_sourceframe ***************************************************** + + 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...............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 with the newly created source frame + added + +*******************************************************************************/ + +static s4 replace_normalize_type_map[] = { +/* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD, +/* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD, +/* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD, +/* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL, +/* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL, +/* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN, +/* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD +}; + + +static void replace_read_executionstate(rplpoint *rp, + executionstate_t *es, + sourcestate_t *ss, + bool topframe) +{ + methodinfo *m; + codeinfo *code; + int count; + int i; + rplalloc *ra; + sourceframe_t *frame; + int topslot; + stackslot_t *sp; + stackslot_t *basesp; + + code = code_find_codeinfo_for_pc(rp->pc); + m = rp->method; + topslot = TOP_IS_NORMAL; + + /* stack pointer */ + + sp = (stackslot_t *) es->sp; + + /* in some cases the top stack slot is passed in REG_ITMP1 */ + + if (rp->type == BBTYPE_EXH) { + topslot = TOP_IS_IN_ITMP1; + } + + /* calculate base stack pointer */ + + basesp = sp + code->stackframesize; + + /* create the source frame */ + + 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->fromrp = rp; + frame->fromcode = code; + + /* read local variables */ + + count = m->maxlocals; + frame->javalocalcount = count; + frame->javalocals = DMNEW(replace_val_t, count); + frame->javalocaltype = DMNEW(u1, count); + + /* mark values as undefined */ + for (i=0; ijavalocals[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;*/ +#if !defined(NDEBUG) + es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL; +#ifdef REG_PV + es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL; +#endif +#endif /* !defined(NDEBUG) */ + + /* read javalocals */ + + count = rp->regalloccount; + ra = rp->regalloc; + + while (count && (i = ra->index) >= 0) { + assert(i < m->maxlocals); + frame->javalocaltype[i] = ra->type; + if (ra->type == TYPE_RET) + frame->javalocals[i].i = ra->regoff; + else + replace_read_value(es, ra, frame->javalocals + i); + ra++; + count--; + } + + /* read instance, if this is the first rplpoint */ + +#if defined(REPLACE_PATCH_DYNAMIC_CALL) + if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) { +#if 1 + /* we are at the start of the method body, so if local 0 is set, */ + /* it is the instance. */ + if (frame->javalocaltype[0] == TYPE_ADR) + frame->instance = frame->javalocals[0]; +#else + rplalloc instra; + methoddesc *md; + + md = rp->method->parseddesc; + assert(md->params); + assert(md->paramcount >= 1); + instra.type = TYPE_ADR; + instra.regoff = md->params[0].regoff; + if (md->params[0].inmemory) { + instra.flags = INMEMORY; + instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT; + } + else { + instra.flags = 0; + } + 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(replace_val_t, count); + frame->javastacktype = DMNEW(u1, count); + +#if !defined(NDEBUG) + /* mark values as undefined */ + for (i=0; ijavastack[i].l = (u8) 0x00dead0000dead00ULL; + frame->javastacktype[i] = TYPE_VOID; + } +#endif /* !defined(NDEBUG) */ + + i = 0; + + /* the first stack slot is special in SBR and EXH blocks */ + + if (topslot == TOP_IS_ON_STACK) { + assert(count); + + assert(ra->index == RPLALLOC_STACK); + assert(ra->type == TYPE_ADR); + frame->javastack[i].p = sp[-1]; + frame->javastacktype[i] = TYPE_ADR; /* XXX RET */ + count--; + i++; + ra++; + } + else if (topslot == TOP_IS_IN_ITMP1) { + assert(count); + + assert(ra->index == RPLALLOC_STACK); + assert(ra->type == TYPE_ADR); + frame->javastack[i].p = es->intregs[REG_ITMP1]; + frame->javastacktype[i] = TYPE_ADR; /* XXX RET */ + count--; + i++; + ra++; + } + else if (topslot == TOP_IS_VOID) { + assert(count); + + assert(ra->index == RPLALLOC_STACK); + frame->javastack[i].l = 0; + frame->javastacktype[i] = TYPE_VOID; + count--; + i++; + ra++; + } + + /* read remaining stack slots */ + + for (; count--; ra++) { + if (ra->index == RPLALLOC_SYNC) { + assert(rp->type == RPLPOINT_TYPE_INLINE); + + /* only read synchronization slots when traversing an inline point */ + + if (!topframe) { + sourceframe_t *calleeframe = frame->down; + assert(calleeframe); + assert(calleeframe->syncslotcount == 0); + assert(calleeframe->syncslots == NULL); + + calleeframe->syncslotcount = 1; + calleeframe->syncslots = DMNEW(replace_val_t, 1); + replace_read_value(es,ra,calleeframe->syncslots); + } + + frame->javastackdepth--; + continue; + } + + assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM); + + /* do not read parameters of calls down the call chain */ + + if (!topframe && ra->index == RPLALLOC_PARAM) { + frame->javastackdepth--; + } + else { + if (ra->type == TYPE_RET) + frame->javastack[i].i = ra->regoff; + else + replace_read_value(es,ra,frame->javastack + i); + frame->javastacktype[i] = ra->type; + i++; + } + } +} + + +/* replace_write_executionstate ************************************************ + + 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 + 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 + +*******************************************************************************/ + +static void replace_write_executionstate(rplpoint *rp, + executionstate_t *es, + sourcestate_t *ss, + bool topframe) +{ + methodinfo *m; + codeinfo *code; + int count; + int i; + rplalloc *ra; + sourceframe_t *frame; + int topslot; + stackslot_t *sp; + stackslot_t *basesp; + + code = code_find_codeinfo_for_pc(rp->pc); + m = rp->method; + topslot = TOP_IS_NORMAL; + + /* pop a source frame */ + + frame = ss->frames; + assert(frame); + ss->frames = frame->down; + + /* calculate stack pointer */ + + sp = (stackslot_t *) es->sp; + + basesp = sp + code->stackframesize; + + /* in some cases the top stack slot is passed in REG_ITMP1 */ + + if (rp->type == BBTYPE_EXH) { + topslot = TOP_IS_IN_ITMP1; + } + + /* write javalocals */ + + ra = rp->regalloc; + count = rp->regalloccount; + + while (count && (i = ra->index) >= 0) { + assert(i < m->maxlocals); + assert(i < frame->javalocalcount); + assert(ra->type == frame->javalocaltype[i]); + if (ra->type == TYPE_RET) { + /* XXX assert that it matches this rplpoint */ + } + else + replace_write_value(es, ra, frame->javalocals + i); + count--; + ra++; + } + + /* write stack slots */ + + i = 0; + + /* the first stack slot is special in SBR and EXH blocks */ + + if (topslot == TOP_IS_ON_STACK) { + assert(count); + + assert(ra->index == RPLALLOC_STACK); + assert(i < frame->javastackdepth); + assert(frame->javastacktype[i] == TYPE_ADR); + sp[-1] = frame->javastack[i].p; + count--; + i++; + ra++; + } + else if (topslot == TOP_IS_IN_ITMP1) { + assert(count); + + assert(ra->index == RPLALLOC_STACK); + assert(i < frame->javastackdepth); + assert(frame->javastacktype[i] == TYPE_ADR); + es->intregs[REG_ITMP1] = frame->javastack[i].p; + count--; + i++; + ra++; + } + else if (topslot == TOP_IS_VOID) { + assert(count); + + assert(ra->index == RPLALLOC_STACK); + assert(i < frame->javastackdepth); + assert(frame->javastacktype[i] == TYPE_VOID); + count--; + i++; + ra++; + } + + /* write remaining stack slots */ + + for (; count--; ra++) { + if (ra->index == RPLALLOC_SYNC) { + assert(rp->type == RPLPOINT_TYPE_INLINE); + + /* only write synchronization slots when traversing an inline point */ + + if (!topframe) { + assert(frame->down); + assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */ + assert(frame->down->syncslots != NULL); + + replace_write_value(es,ra,frame->down->syncslots); + } + continue; + } + + assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM); + + /* do not write parameters of calls down the call chain */ + + 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); + assert(ra->type == frame->javastacktype[i]); + if (ra->type == TYPE_RET) { + /* XXX assert that it matches this rplpoint */ + } + else { + replace_write_value(es,ra,frame->javastack + i); + } + i++; + } + } + + /* set new pc */ + + es->pc = rp->pc; +} + + +/* 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. + + *** This function imitates the effects of the method epilog *** + *** and returning from the method call. *** + + IN: + es...............execution state + + OUT: + *es..............the execution state after popping the stack frame + NOTE: es->code and es->pv are NOT updated. + +*******************************************************************************/ + +void md_pop_stackframe(executionstate_t *es) +{ + u1 *ra; + s4 ra_align_off; + s4 reg; + s4 i; + stackslot_t *basesp; + stackslot_t *sp; + + assert(es->code); + + /* alignment offset of RA */ + + ra_align_off = 0; +#if defined(REPLACE_RA_BETWEEN_FRAMES) + if (es->code->stackframesize) + ra_align_off = SIZE_OF_STACKSLOT - SIZEOF_VOID_P; +#endif + + /* read the return address */ + +#if defined(REPLACE_LEAFMETHODS_RA_REGISTER) + if (code_is_leafmethod(es->code)) + ra = es->ra; + else +#endif + ra = (u1*) 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; + + /* restore return address, if part of frame */ + +#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 */ + + reg = INT_REG_CNT; + for (i=0; icode->savedintcount; ++i) { + while (nregdescint[--reg] != REG_SAV) + ; + es->intregs[reg] = *--basesp; + } + + /* restore saved flt registers */ + + /* XXX align? */ + reg = FLT_REG_CNT; + for (i=0; icode->savedfltcount; ++i) { + while (nregdescfloat[--reg] != REG_SAV) + ; + basesp -= STACK_SLOTS_PER_FLOAT; + es->fltregs[reg] = *(double*)basesp; + } + +#if defined(HAS_ADDRESS_REGISTER_FILE) + /* restore saved adr registers */ + + reg = ADR_REG_CNT; + for (i=0; icode->savedadrcount; ++i) { + while (nregdescadr[--reg] != REG_SAV) + ; + es->adrregs[reg] = *--basesp; + } +#endif + + /* adjust the stackpointer */ + + es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize; + +#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; iintregs[i] = (ptrint) 0x33dead3333dead33ULL; + for (i=0; ifltregs[i]) = 0x33dead3333dead33ULL; +# if defined(HAS_ADDRESS_REGISTER_FILE) + for (i=0; iadrregs[i] = (ptrint) 0x33dead3333dead33ULL; +# endif +#endif /* !defined(NDEBUG) */ +} + + +/* md_push_stackframe ********************************************************** + + 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: + 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. + +*******************************************************************************/ + +void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra) +{ + s4 reg; + s4 i; + stackslot_t *basesp; + stackslot_t *sp; + + assert(es); + assert(calleecode); + + /* write the return address */ + +#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 */ + + es->ra = (u1*) (ptrint) ra; + + /* 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 */ + + /* XXX may not invalidate linkage area used by native code! */ + +#if !defined(NDEBUG) && 0 + for (i=0; i< (basesp - sp) && i < 1; ++i) { + sp[i] = 0xdeaddeadU; + } +#endif + +#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 + + /* save the return address register */ + +#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 */ + +#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 */ + + /* save int registers */ + + reg = INT_REG_CNT; + for (i=0; isavedintcount; ++i) { + while (nregdescint[--reg] != REG_SAV) + ; + *--basesp = es->intregs[reg]; + + /* XXX may not clobber saved regs used by native code! */ +#if !defined(NDEBUG) && 0 + es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL; +#endif + } + + /* save flt registers */ + + /* XXX align? */ + reg = FLT_REG_CNT; + for (i=0; isavedfltcount; ++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; isavedadrcount; ++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; + 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; isyncslots[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 */ + + void* pv = md_codegen_get_pv_from_pc(ra); + DOLOG( printf("PV = %p\n", pv); ); + + code = code_get_codeinfo_for_pv(pv); + DOLOG( printf("CODE = %p\n", (void*) code); ); + + /* return NULL if we reached native code */ + + es->pv = (uint8_t*) 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 + && (void*) vftbl->table[pd->m->vftblindex] != (void*) (uintptr_t) &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 = (u1*) 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.a) { + DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); ); + replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint); + return; + } + + /* get the vftbl */ + + obj = calleeframe->instance.a; + vftbl = obj->vftbl; + + assert(vftbl->clazz->vftbl == vftbl); + + DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->clazz); ); + + replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint); + } + else { + /* the call was statically bound */ + +#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 "); + } +} + + +/* replace_push_activation_record ********************************************** + + Push a stack frame onto the execution state. + + *** This function imitates the effects of a call and the *** + *** method prolog of the callee. *** + + IN: + es...............execution state + rpcall...........the replacement point at the call site + callerframe......source frame of the caller, or NULL for creating the + first frame + calleeframe......source frame of the callee, must have been mapped + + OUT: + *es..............the execution state after pushing the stack frame + +*******************************************************************************/ + +void replace_push_activation_record(executionstate_t *es, + rplpoint *rpcall, + sourceframe_t *callerframe, + sourceframe_t *calleeframe) +{ + s4 i; + s4 count; + stackslot_t *sp; + u1 *ra; + codeinfo *calleecode; + + assert(es); + assert(!rpcall || callerframe); + assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL); + assert(!rpcall || rpcall == callerframe->torp); + assert(calleeframe); + assert(!callerframe || calleeframe == callerframe->down); + + /* the compilation unit we are entering */ + + calleecode = calleeframe->tocode; + assert(calleecode); + + /* calculate the return address */ + + if (rpcall) + ra = rpcall->pc + rpcall->callsize; + else + ra = es->pc + 1 /* XXX this is ugly */; + + /* push the stackframe */ + + md_push_stackframe(es, calleecode, ra); + + /* we move into a new code unit, set code, PC, PV */ + + es->code = calleecode; + 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; imemuse + i] = calleeframe->syncslots[i].p; + } + + /* redirect future invocations */ + + if (callerframe && rpcall) { +#if defined(REPLACE_PATCH_ALL) + if (rpcall->type == callerframe->fromrp->type) +#else + if (rpcall == callerframe->fromrp) +#endif + replace_patch_future_calls(ra, callerframe, calleeframe); + } +} + + +/* replace_find_replacement_point ********************************************** + + Find the replacement point in the given code corresponding to the + position given in the source frame. + + IN: + code.............the codeinfo in which to search the rplpoint + frame............the source frame defining the position to look for + parent...........parent replacement point to match + + RETURN VALUE: + the replacement point + +*******************************************************************************/ + +rplpoint * replace_find_replacement_point(codeinfo *code, + sourceframe_t *frame, + rplpoint *parent) +{ + methodinfo *m; + rplpoint *rp; + s4 i; + s4 j; + s4 stacki; + rplalloc *ra; + + assert(code); + assert(frame); + + DOLOG( printf("searching replacement point for:\n"); + replace_source_frame_println(frame); ); + + m = frame->method; + + DOLOG( printf("code = %p\n", (void*)code); ); + + rp = code->rplpoints; + i = code->rplpointcount; + while (i--) { + if (rp->id == frame->id && rp->method == frame->method + && rp->parent == parent + && replace_normalize_type_map[rp->type] == frame->type) + { + /* check if returnAddresses match */ + /* XXX optimize: only do this if JSRs in method */ + DOLOG( printf("checking match for:"); + replace_replacement_point_println(rp, 1); fflush(stdout); ); + ra = rp->regalloc; + stacki = 0; + for (j = rp->regalloccount; j--; ++ra) { + if (ra->type == TYPE_RET) { + if (ra->index == RPLALLOC_STACK) { + assert(stacki < frame->javastackdepth); + 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].i != ra->regoff) + goto no_match; + } + } + } + + /* found */ + return rp; + } +no_match: + rp++; + } + +#if !defined(NDEBUG) + printf("candidate replacement points were:\n"); + rp = code->rplpoints; + i = code->rplpointcount; + for (; i--; ++rp) { + replace_replacement_point_println(rp, 1); + } +#endif + + vm_abort("no matching replacement point found"); + return NULL; /* NOT REACHED */ +} + + +/* replace_find_replacement_point_for_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 + pc...............the machine code PC + + RETURN VALUE: + the replacement point found, or + NULL if no replacement point was found + +*******************************************************************************/ + +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; irplpointcount; ++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) ? (((uintptr_t) sfi->sp) - ((uintptr_t) es->sp)) : 0; + assert(frame->nativeframesize >= 0); + + /* remember values of saved registers */ + + j = 0; + for (i=0; inativesavint[j++] = es->intregs[i]; + } + + j = 0; + for (i=0; inativesavflt[j++] = es->fltregs[i]; + } + +#if defined(HAS_ADDRESS_REGISTER_FILE) + j = 0; + for (i=0; inativesavadr[j++] = es->adrregs[i]; + } +#endif + + /* restore saved registers */ + +#if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE) + j = 0; + for (i=0; iintregs[i] = sfi->intregs[j++]; + } +#else + /* XXX we don't have them, yet, in the sfi, so clear them */ + + for (i=0; iintregs[i] = 0; + } +#endif + + /* XXX we don't have float registers in the sfi, so clear them */ + + for (i=0; ifltregs[i] = 0.0; + } + +#if defined(HAS_ADDRESS_REGISTER_FILE) +# if defined(ENABLE_GC_CACAO) + j = 0; + for (i=0; iadrregs[i] = sfi->adrregs[j++]; + } +# else + for (i=0; iadrregs[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 = (uint8_t*) (((uintptr_t) sfi->sp) + (*(s4 *) (((uintptr_t) sfi->pv) + FrameSize))); +#if defined(REPLACE_RA_BETWEEN_FRAMES) + es->sp += SIZE_OF_STACKSLOT; /* skip return address */ +#endif + es->pv = (uint8_t*) md_codegen_get_pv_from_pc(sfi->ra); + es->pc = (uint8_t*) (((uintptr_t) ((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 *) (((uintptr_t) 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; isfi->intregs[j++] = es->intregs[i]; + } +# else + for (i=0; isfi->adrregs[j++] = es->adrregs[i]; + } +# endif + + /* XXX leave float registers untouched here */ +#endif + + /* restore saved registers */ + + j = 0; + for (i=0; iintregs[i] = frame->nativesavint[j++]; + } + + j = 0; + for (i=0; ifltregs[i] = frame->nativesavflt[j++]; + } + +#if defined(HAS_ADDRESS_REGISTER_FILE) + j = 0; + for (i=0; iadrregs[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 ************************************************ + + Recover the source state from the given replacement point and execution + state. + + IN: + 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: + the source state + +*******************************************************************************/ + +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 + + /* create the source frame structure in dump memory */ + + ss = DNEW(sourcestate_t); + ss->frames = NULL; + + /* each iteration of the loop recovers one source frame */ + + depth = 0; + locked = false; + + while (rp || sfi) { + + 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 */ + + DOLOG( printf("recovering source state for%s:\n", + (ss->frames == NULL) ? " TOPFRAME" : ""); + replace_replacement_point_println(rp, 1); ); + + 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) { + /* this frame is in inlined code */ + + DOLOG( printf("INLINED!\n"); ); + + rp = rp->parent; + + assert(rp->type == RPLPOINT_TYPE_INLINE); + REPLACE_COUNT(stat_unroll_inline); + } + else { + /* 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("REACHED NATIVE CODE\n"); ); + + rp = NULL; + +#if !defined(ENABLE_GC_CACAO) + break; /* XXX remove to activate native frames */ +#endif + continue; + } + + /* 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"); + + DOLOG( printf("found replacement point.\n"); + replace_replacement_point_println(rp, 1); ); + + assert(rp->type == RPLPOINT_TYPE_CALL); + REPLACE_COUNT(stat_unroll_call); + } + } /* end loop over source frames */ + + REPLACE_COUNT_DIST(stat_dist_frames, depth); + + return ss; +} + + +/* replace_map_source_state **************************************************** + + Map each source frame in the given source state to a target replacement + point and compilation unit. If no valid code is available for a source + frame, it is (re)compiled. + + IN: + ss...............the source state + + OUT: + ss...............the source state, modified: The `torp` and `tocode` + fields of each source frame are set. + + RETURN VALUE: + true.............everything went ok + false............an exception has been thrown + +*******************************************************************************/ + +static bool replace_map_source_state(sourcestate_t *ss) +{ + sourceframe_t *frame; + codeinfo *code; + rplpoint *rp; + rplpoint *parent; /* parent of inlined rplpoint */ +#if defined(REPLACE_STATISTICS) + codeinfo *oldcode; +#endif + + parent = NULL; + code = NULL; + + /* iterate over the source frames from outermost to innermost */ + + for (frame = ss->frames; frame != NULL; frame = frame->down) { + + /* XXX skip native frames */ + + if (REPLACE_IS_NATIVE_FRAME(frame)) { + parent = NULL; + continue; + } + + /* map frames which are not already mapped */ + + if (frame->tocode) { + code = frame->tocode; + rp = frame->torp; + assert(rp); + } + else { + assert(frame->torp == NULL); + + if (parent == NULL) { + /* find code for this frame */ + +#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) + 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; + } + } + + return true; +} + + +/* 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. + + !!! CAUTION: This function rewrites the machine stack !!! + + THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA! + + IN: + ss...............the source state. Must have been mapped by + replace_map_source_state before. + es...............the base execution state on which to build + + OUT: + *es..............the new execution state + +*******************************************************************************/ + +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 (ss->frames) { + + 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); + + 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; + +#if defined(ENABLE_VMLOG) + vmlog_cacao_rerol_method(ss->frames->method); +#endif + + replace_write_executionstate(rp, es, ss, ss->frames->down == NULL); + + DOLOG( executionstate_println(es); ); + + if (rp->type == RPLPOINT_TYPE_CALL) { + parent = NULL; + } + else { + /* inlining */ + parent = rp; + } + } +} + + +/* 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! + + IN: + rp...............replacement point that has been reached + es...............execution state read by signal handler + +*******************************************************************************/ + +static void replace_me(rplpoint *rp, executionstate_t *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; + + origcode = es->code; + origrp = rp; + +#if defined(ENABLE_TLH) + /*printf("Replacing in %s/%s\n", rp->method->clazz->name->text, rp->method->name->text);*/ +#endif + + /*if (strcmp(rp->method->clazz->name->text, "antlr/AlternativeElement") == 0 && strcmp(rp->method->name->text, "getAutoGenType") ==0) opt_TraceReplacement = 2; else opt_TraceReplacement = 0;*/ + + 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_COUNT(stat_replacements); + + /* mark start of dump memory area */ + + DMARKER; + + /* Get the stackframeinfo for the current thread. */ + + sfi = threads_get_current_stackframeinfo(); + + /* recover source state */ + + ss = replace_recover_source_state(rp, sfi, es); + +#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO) + /* if there is a collection pending, we assume the replacement point should + suspend this thread */ + + if (gc_pending) { + + thread = THREADOBJECT; + + DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); ); + + /* map the sourcestate using the identity mapping */ + replace_map_source_state_identity(ss); + + /* since we enter the same method again, we turn off rps now */ + /* XXX michi: can we really do this? what if the rp was active before + we activated it for the gc? */ + replace_deactivate_replacement_points(origcode); + + /* remember executionstate and sourcestate for this thread */ + GC_EXECUTIONSTATE = es; + GC_SOURCESTATE = ss; + + /* really suspend this thread now (PC = 0) */ + threads_suspend_ack(NULL, NULL); + + DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); ); + + } else { +#endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/ + + /* map the source state */ + + if (!replace_map_source_state(ss)) + vm_abort("exception during method replacement"); + + DOLOG( replace_sourcestate_println(ss); ); + + DOLOG_SHORT( replace_sourcestate_println_short(ss); ); + +#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 + +#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO) + } +#endif + + /* build the new execution state */ + + replace_build_execution_state(ss, es); + +#if !defined(NDEBUG) + /* continue execution after patched machine code, if testing mode enabled */ + + if (opt_TestReplacement) + es->pc += REPLACEMENT_PATCH_SIZE; +#endif + + /* release dump area */ + + DRELEASE; +} + + +/* 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! + + 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; +#if defined(ENABLE_RT_TIMING) + struct timespec time_start, time_end; +#endif + + /* 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, (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN)); + + /* check if the replacement point belongs to given PC and is active */ + + if ((rp != NULL) && (rp->pc == pc) + && (rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))) { + + DOLOG( printf("valid replacement point\n"); ); + +#if !defined(NDEBUG) + executionstate_sanity_check(context); +#endif + + /* set codeinfo pointer in execution state */ + + es.code = code; + + /* read execution state from current context */ + + md_executionstate_read(&es, context); + + DOLOG( printf("REPLACEMENT READ: "); + executionstate_println(&es); ); + + /* 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 + + /* 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; +} + + +/******************************************************************************/ +/* 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; + + /* Get the stackframeinfo of this thread. */ + + assert(thread == THREADOBJECT); + + sfi = threads_get_current_stackframeinfo(); + + /* 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 */ + + /* we assume we are in a native (no replacement point)! */ + ss = replace_recover_source_state(NULL, sfi, es); + + /* 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 + +#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. */ +/******************************************************************************/ + + +/* statistics *****************************************************************/ + +#if defined(REPLACE_STATISTICS) +static void print_freq(FILE *file,int *array,int limit) +{ + int i; + int sum = 0; + int cum = 0; + for (i=0; i=%3d: %8d\n",limit,array[limit]); +} +#endif /* defined(REPLACE_STATISTICS) */ + + +#if defined(REPLACE_STATISTICS) + +#define REPLACE_PRINT_DIST(name, array) \ + printf(" " name " distribution:\n"); \ + print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1); + +void replace_print_statistics(void) +{ + printf("replacement statistics:\n"); + printf(" # of replacements: %d\n", stat_replacements); + printf(" # of frames: %d\n", stat_frames); + printf(" # of recompilations: %d\n", stat_recompile); + printf(" patched static calls:%d\n", stat_staticpatch); + printf(" unrolled inlines: %d\n", stat_unroll_inline); + printf(" unrolled calls: %d\n", stat_unroll_call); + REPLACE_PRINT_DIST("frame depth", stat_dist_frames); + REPLACE_PRINT_DIST("locals per frame", stat_dist_locals); + REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr); + REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim); + REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret); + REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void); + REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack); + REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr); + REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim); + REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret); + printf("\n"); + printf(" # of methods: %d\n", stat_methods); + printf(" # of replacement points: %d\n", stat_rploints); + printf(" # of regallocs: %d\n", stat_regallocs); + printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints); + printf(" per method: %f\n", (double)stat_regallocs / stat_methods); + REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints); + printf("\n"); + +} +#endif /* defined(REPLACE_STATISTICS) */ + + +#if defined(REPLACE_STATISTICS) +static void replace_statistics_source_frame(sourceframe_t *frame) +{ + int adr = 0; + int ret = 0; + int prim = 0; + int vd = 0; + int n = 0; + int i; + + for (i=0; ijavalocalcount; ++i) { + switch (frame->javalocaltype[i]) { + case TYPE_ADR: adr++; break; + case TYPE_RET: ret++; break; + case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break; + case TYPE_VOID: vd++; break; + default: assert(0); + } + n++; + } + REPLACE_COUNT_DIST(stat_dist_locals, n); + REPLACE_COUNT_DIST(stat_dist_locals_adr, adr); + REPLACE_COUNT_DIST(stat_dist_locals_void, vd); + REPLACE_COUNT_DIST(stat_dist_locals_ret, ret); + REPLACE_COUNT_DIST(stat_dist_locals_prim, prim); + adr = ret = prim = n = 0; + for (i=0; ijavastackdepth; ++i) { + switch (frame->javastacktype[i]) { + case TYPE_ADR: adr++; break; + case TYPE_RET: ret++; break; + case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break; + } + n++; + } + REPLACE_COUNT_DIST(stat_dist_stack, n); + REPLACE_COUNT_DIST(stat_dist_stack_adr, adr); + REPLACE_COUNT_DIST(stat_dist_stack_ret, ret); + REPLACE_COUNT_DIST(stat_dist_stack_prim, prim); +} +#endif /* defined(REPLACE_STATISTICS) */ + + +/* debugging helpers **********************************************************/ + +/* replace_replacement_point_println ******************************************* + + Print replacement point info. + + IN: + rp...............the replacement point to print + +*******************************************************************************/ + +#if !defined(NDEBUG) + +#define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?') + +static const char *replace_type_str[] = { + "STD", + "EXH", + "SBR", + "CALL", + "INLINE", + "RETURN", + "BODY" +}; + +void replace_replacement_point_println(rplpoint *rp, int depth) +{ + int j; + int index; + + if (!rp) { + printf("(rplpoint *)NULL\n"); + return; + } + + for (j=0; jid, (void*)rp,rp->pc,rp->callsize, + 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); + for (j=0; jregalloccount); + + for (j=0; jregalloccount; ++j) { + if (j) + putchar(' '); + index = rp->regalloc[j].index; + switch (index) { + case RPLALLOC_STACK: printf("S"); break; + case RPLALLOC_PARAM: printf("P"); break; + case RPLALLOC_SYNC : printf("Y"); break; + default: printf("%d", index); + } + printf(":%1c:", TYPECHAR(rp->regalloc[j].type)); + if (rp->regalloc[j].type == TYPE_RET) { + printf("ret(L%03d)", rp->regalloc[j].regoff); + } + else { + show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff); + } + } + + printf("]\n"); + for (j=0; jmethod); + + printf("\n"); +} +#endif /* !defined(NDEBUG) */ + + +/* replace_show_replacement_points ********************************************* + + Print replacement point info. + + IN: + code.............codeinfo whose replacement points should be printed. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void replace_show_replacement_points(codeinfo *code) +{ + int i; + int depth; + rplpoint *rp; + rplpoint *parent; + + if (!code) { + printf("(codeinfo *)NULL\n"); + return; + } + + printf("\treplacement points: %d\n",code->rplpointcount); + + 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"); + + for (i=0; irplpointcount; ++i) { + rp = code->rplpoints + i; + + depth = 1; + parent = rp->parent; + while (parent) { + depth++; + parent = parent->parent; + } + replace_replacement_point_println(rp, depth); + } +} +#endif + + +#if !defined(NDEBUG) +static void java_value_print(s4 type, replace_val_t value) +{ + java_object_t *obj; + utf *u; + + printf("%016llx",(unsigned long long) value.l); + + if (type < 0 || type > TYPE_RET) + printf(" ", type); + else + printf(" %s", show_jit_type_names[type]); + + if (type == TYPE_ADR && value.a != NULL) { + obj = value.a; + putchar(' '); + utf_display_printable_ascii_classname(obj->vftbl->clazz->name); + + if (obj->vftbl->clazz == class_java_lang_String) { + printf(" \""); + u = javastring_toutf(obj, false); + utf_display_printable_ascii(u); + printf("\""); + } + } + 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,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; inativesavint[j++]); + } + + j = 0; + for (i=0; inativesavflt[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.a) { + printf("\tinstance: "); + java_value_print(TYPE_ADR, frame->instance); + printf("\n"); + } + + if (frame->javalocalcount) { + printf("\tlocals (%d):\n",frame->javalocalcount); + for (i=0; ijavalocalcount; ++i) { + t = frame->javalocaltype[i]; + if (t == TYPE_VOID) { + printf("\tlocal[ %2d] = void\n",i); + } + else { + printf("\tlocal[%c%2d] = ",TYPECHAR(t),i); + java_value_print(t, frame->javalocals[i]); + printf("\n"); + } + } + printf("\n"); + } + + if (frame->javastackdepth) { + printf("\tstack (depth %d):\n",frame->javastackdepth); + for (i=0; ijavastackdepth; ++i) { + t = frame->javastacktype[i]; + if (t == TYPE_VOID) { + printf("\tstack[%2d] = void", i); + } + else { + printf("\tstack[%2d] = ",i); + java_value_print(frame->javastacktype[i], frame->javastack[i]); + printf("\n"); + } + } + printf("\n"); + } + + if (frame->syncslotcount) { + printf("\tsynchronization slots (%d):\n",frame->syncslotcount); + for (i=0; isyncslotcount; ++i) { + printf("\tslot[%2d] = ",i); +#ifdef HAS_4BYTE_STACKSLOT + printf("%08lx\n",(unsigned long) frame->syncslots[i].p); +#else + printf("%016llx\n",(unsigned long long) frame->syncslots[i].p); +#endif + } + printf("\n"); + } + + if (frame->fromcode) { + printf("\tfrom %p ", (void*)frame->fromcode); + method_println(frame->fromcode->m); + } + if (frame->tocode) { + printf("\tto %p ", (void*)frame->tocode); + method_println(frame->tocode->m); + } + + if (frame->fromrp) { + printf("\tfrom replacement point:\n"); + replace_replacement_point_println(frame->fromrp, 2); + } + if (frame->torp) { + printf("\tto replacement point:\n"); + replace_replacement_point_println(frame->torp, 2); + } + + printf("\n"); +} +#endif /* !defined(NDEBUG) */ + + +/* replace_sourcestate_println ************************************************* + + Print source state + + IN: + ss...............the source state to print + +*******************************************************************************/ + +#if !defined(NDEBUG) +void replace_sourcestate_println(sourcestate_t *ss) +{ + int i; + sourceframe_t *frame; + + if (!ss) { + printf("(sourcestate_t *)NULL\n"); + return; + } + + printf("sourcestate_t:\n"); + + for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) { + printf(" frame %d:\n", i); + replace_source_frame_println(frame); + } +} +#endif + + +/* replace_sourcestate_println_short ******************************************* + + Print a compact representation of the given source state. + + IN: + ss...............the source state to print + +*******************************************************************************/ + +#if !defined(NDEBUG) +void replace_sourcestate_println_short(sourcestate_t *ss) +{ + sourceframe_t *frame; + + 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) ? '=' : '+'); + } + + printf("%s", replace_type_str[frame->fromrp->type]); + + if (frame->torp && frame->torp->type != frame->fromrp->type) + printf("->%s", replace_type_str[frame->torp->type]); + + if (frame->tocode != frame->fromcode) + printf(" (%p->%p/%d) ", + (void*) frame->fromcode, (void*) frame->tocode, + frame->fromrp->id); + else + printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id); + + method_println(frame->method); + } +} +#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 + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c++ + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */ diff --git a/src/vm/jit/replace.h b/src/vm/jit/replace.h deleted file mode 100644 index e27c6ce68..000000000 --- a/src/vm/jit/replace.h +++ /dev/null @@ -1,289 +0,0 @@ -/* src/vm/jit/replace.h - on-stack replacement of methods - - Copyright (C) 1996-2005, 2006, 2007, 2008 - CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO - - This file is part of CACAO. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. - -*/ - - -#ifndef _REPLACE_H -#define _REPLACE_H - -#include "config.h" -#include "vm/types.h" - -#if !defined(ENABLE_REPLACEMENT) - -/*** macros for the codegens (disabled version) ************************/ - -#define REPLACEMENT_POINTS_INIT(cd, jd) -#define REPLACEMENT_POINTS_RESET(cd, jd) -#define REPLACEMENT_POINT_BLOCK_START(cd, bptr) -#define REPLACEMENT_POINT_INLINE_START(cd, iptr) -#define REPLACEMENT_POINT_INLINE_BODY(cd, iptr) -#define REPLACEMENT_POINT_RETURN(cd, iptr) -#define REPLACEMENT_POINT_INVOKE(cd, iptr) -#define REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr) -#define REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr) -#define REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr) - -#else /* defined(ENABLE_REPLACEMENT) */ - -/* forward typedefs ***********************************************************/ - -typedef struct rplalloc rplalloc; -typedef struct rplpoint rplpoint; -typedef struct sourcestate_t sourcestate_t; -typedef struct sourceframe_t sourceframe_t; -typedef union replace_val_t replace_val_t; - -#include "arch.h" -#include "md-abi.h" - -#include "vm/method.h" - -#include "vm/jit/reg.h" -#include "vm/jit/stacktrace.hpp" - - -/*** structs *********************************************************/ - -#define RPLALLOC_STACK -1 -#define RPLALLOC_PARAM -2 -#define RPLALLOC_SYNC -3 - -/* `rplalloc` is a compact struct for register allocation info */ - -/* XXX optimize this for space efficiency */ -struct rplalloc { - s4 index; /* local index, -1 for stack slot */ - s4 regoff; /* register index / stack slot offset */ - unsigned int flags:4; /* OR of (INMEMORY,...) */ - unsigned int type:4; /* TYPE_... constant */ -}; - -#if INMEMORY > 0x08 -#error value of INMEMORY is too big to fit in rplalloc.flags -#endif - - -/* XXX what to do about overlapping rplpoints? */ -/* CAUTION: Do not change the numerical values. These are used as */ -/* indices into replace_normalize_type_map. */ -#define RPLPOINT_TYPE_STD BBTYPE_STD -#define RPLPOINT_TYPE_EXH BBTYPE_EXH -#define RPLPOINT_TYPE_SBR BBTYPE_SBR -#define RPLPOINT_TYPE_CALL 3 -#define RPLPOINT_TYPE_INLINE 4 -#define RPLPOINT_TYPE_RETURN 5 -#define RPLPOINT_TYPE_BODY 6 - -#define RPLPOINT_FLAG_NOTRAP 0x01 /* rplpoint cannot be trapped */ -#define RPLPOINT_FLAG_COUNTDOWN 0x02 /* count down hits */ -#define RPLPOINT_FLAG_ACTIVE 0x08 /* trap is active */ - - -#if !defined(NDEBUG) -#define RPLPOINT_CHECK(type) , RPLPOINT_TYPE_##type -#define RPLPOINT_CHECK_BB(bptr) , (bptr)->type -#else -#define RPLPOINT_CHECK(type) -#define RPLPOINT_CHECK_BB(bptr) -#endif - - -/* An `rplpoint` represents a replacement point in a compiled method */ - -struct rplpoint { - u1 *pc; /* machine code PC of this point */ - methodinfo *method; /* source method this point is in */ - rplpoint *parent; /* rplpoint of the inlined body */ /* XXX unify with code */ - rplalloc *regalloc; /* pointer to register index table */ - s4 id; /* id of the rplpoint within method */ - s4 callsize; /* size of call code in bytes */ - unsigned int regalloccount:20; /* number of local allocations */ - unsigned int type:4; /* RPLPOINT_TYPE_... constant */ - unsigned int flags:8; /* OR of RPLPOINT_... constants */ -}; - - -union replace_val_t { - s4 i; - s8 l; - ptrint p; - struct { - u4 lo; - u4 hi; - } words; - float f; - double d; - java_object_t *a; -}; - - -struct sourceframe_t { - sourceframe_t *down; /* source frame down the call chain */ - - methodinfo *method; /* method this frame is in */ - s4 id; - s4 type; - - /* values */ - replace_val_t instance; - - replace_val_t *javastack; /* values of stack vars */ - u1 *javastacktype; /* types of stack vars */ - s4 javastackdepth; /* number of stack vars */ - - replace_val_t *javalocals; /* values of javalocals */ - u1 *javalocaltype; /* types of javalocals */ - s4 javalocalcount; /* number of javalocals */ - - replace_val_t *syncslots; - s4 syncslotcount; /* XXX do we need more than one? */ - - /* mapping info */ - rplpoint *fromrp; /* rplpoint used to read this frame */ - codeinfo *fromcode; /* code this frame was using */ - rplpoint *torp; /* rplpoint this frame was mapped to */ - codeinfo *tocode; /* code this frame was mapped to */ - - /* info for native frames */ - stackframeinfo_t *sfi; /* sfi for native frames, otherwise NULL */ - s4 nativeframesize; /* size (bytes) of native frame */ - u1 *nativepc; - ptrint nativesavint[INT_SAV_CNT]; /* XXX temporary */ - double nativesavflt[FLT_REG_CNT]; /* XXX temporary */ -#if defined(HAS_ADDRESS_REGISTER_FILE) - ptrint nativesavadr[ADR_SAV_CNT]; /* XXX temporary */ -#endif -}; - -#define REPLACE_IS_NATIVE_FRAME(frame) ((frame)->sfi != NULL) -#define REPLACE_IS_JAVA_FRAME(frame) ((frame)->sfi == NULL) - - -struct sourcestate_t { - sourceframe_t *frames; /* list of source frames, from bottom up */ -}; - - -/*** macros for the codegens *******************************************/ - -#define REPLACEMENT_POINTS_INIT(cd, jd) \ - if (!replace_create_replacement_points(jd)) \ - return false; \ - (cd)->replacementpoint = (jd)->code->rplpoints; - -#define REPLACEMENT_POINTS_RESET(cd, jd) \ - (cd)->replacementpoint = (jd)->code->rplpoints; - -#define REPLACEMENT_POINT_BLOCK_START(cd, bptr) \ - if ((bptr)->bitflags & BBFLAG_REPLACEMENT) \ - codegen_set_replacement_point((cd) RPLPOINT_CHECK_BB(bptr)); - -#define REPLACEMENT_POINT_INLINE_START(cd, iptr) \ - codegen_set_replacement_point(cd RPLPOINT_CHECK(INLINE)); - -#define REPLACEMENT_POINT_INLINE_BODY(cd, iptr) \ - codegen_set_replacement_point_notrap(cd RPLPOINT_CHECK(BODY)); - -#define REPLACEMENT_POINT_RETURN(cd, iptr) \ - codegen_set_replacement_point(cd RPLPOINT_CHECK(RETURN)); - -#define REPLACEMENT_POINT_INVOKE(cd, iptr) \ - codegen_set_replacement_point(cd RPLPOINT_CHECK(CALL)); - -#define REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr) \ - if (iptr->opc != ICMD_BUILTIN) \ - cd->replacementpoint[-1].callsize = (cd->mcodeptr - cd->mcodebase)\ - - (ptrint) cd->replacementpoint[-1].pc; - - -/*** macros for the codegens (for GC) **********************************/ - -#if defined(ENABLE_GC_CACAO) - -#define REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr) \ - codegen_set_replacement_point(cd RPLPOINT_CHECK(CALL)); - -#define REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr) \ - if (iptr->opc == ICMD_BUILTIN) \ - cd->replacementpoint[-1].callsize = (cd->mcodeptr - cd->mcodebase)\ - - (ptrint) cd->replacementpoint[-1].pc; - -#else /* defined(ENABLE_GC_CACAO) */ - -#define REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr) -#define REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr) - -#endif /* defined(ENABLE_GC_CACAO) */ - - -/*** prototypes ********************************************************/ - -#ifdef __cplusplus -extern "C" { -#endif - -bool replace_create_replacement_points(jitdata *jd); -void replace_free_replacement_points(codeinfo *code); - -void replace_activate_replacement_points(codeinfo *code, bool mappable); -void replace_deactivate_replacement_points(codeinfo *code); - -bool replace_me_wrapper(u1 *pc, void *context); - -#if !defined(NDEBUG) -void replace_show_replacement_points(codeinfo *code); -void replace_replacement_point_println(rplpoint *rp, int depth); -void replace_sourcestate_println(sourcestate_t *ss); -void replace_sourcestate_println_short(sourcestate_t *ss); -void replace_source_frame_println(sourceframe_t *frame); -#endif - -/* machine dependent functions (code in ARCH_DIR/md.c) */ - -#if defined(ENABLE_JIT) -void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert); -#endif - -#endif /* defined(ENABLE_REPLACEMENT) */ - -#ifdef __cplusplus -} -#endif - -#endif /* _REPLACE_H */ - - -/* - * 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 - * Emacs will automagically detect them. - * --------------------------------------------------------------------- - * Local variables: - * mode: c - * indent-tabs-mode: t - * c-basic-offset: 4 - * tab-width: 4 - * End: - * vim:noexpandtab:sw=4:ts=4: - */ diff --git a/src/vm/jit/replace.hpp b/src/vm/jit/replace.hpp new file mode 100644 index 000000000..adad8cd1e --- /dev/null +++ b/src/vm/jit/replace.hpp @@ -0,0 +1,289 @@ +/* src/vm/jit/replace.hpp - on-stack replacement of methods + + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + + This file is part of CACAO. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + +*/ + + +#ifndef _REPLACE_HPP +#define _REPLACE_HPP + +#include "config.h" +#include "vm/types.h" + +#if !defined(ENABLE_REPLACEMENT) + +/*** macros for the codegens (disabled version) ************************/ + +#define REPLACEMENT_POINTS_INIT(cd, jd) +#define REPLACEMENT_POINTS_RESET(cd, jd) +#define REPLACEMENT_POINT_BLOCK_START(cd, bptr) +#define REPLACEMENT_POINT_INLINE_START(cd, iptr) +#define REPLACEMENT_POINT_INLINE_BODY(cd, iptr) +#define REPLACEMENT_POINT_RETURN(cd, iptr) +#define REPLACEMENT_POINT_INVOKE(cd, iptr) +#define REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr) +#define REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr) +#define REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr) + +#else /* defined(ENABLE_REPLACEMENT) */ + +/* forward typedefs ***********************************************************/ + +typedef struct rplalloc rplalloc; +typedef struct rplpoint rplpoint; +typedef struct sourcestate_t sourcestate_t; +typedef struct sourceframe_t sourceframe_t; +typedef union replace_val_t replace_val_t; + +#include "arch.h" +#include "md-abi.h" + +#include "vm/method.h" + +#include "vm/jit/reg.h" +#include "vm/jit/stacktrace.hpp" + + +/*** structs *********************************************************/ + +#define RPLALLOC_STACK -1 +#define RPLALLOC_PARAM -2 +#define RPLALLOC_SYNC -3 + +/* `rplalloc` is a compact struct for register allocation info */ + +/* XXX optimize this for space efficiency */ +struct rplalloc { + s4 index; /* local index, -1 for stack slot */ + s4 regoff; /* register index / stack slot offset */ + unsigned int flags:4; /* OR of (INMEMORY,...) */ + unsigned int type:4; /* TYPE_... constant */ +}; + +#if INMEMORY > 0x08 +#error value of INMEMORY is too big to fit in rplalloc.flags +#endif + + +/* XXX what to do about overlapping rplpoints? */ +/* CAUTION: Do not change the numerical values. These are used as */ +/* indices into replace_normalize_type_map. */ +#define RPLPOINT_TYPE_STD BBTYPE_STD +#define RPLPOINT_TYPE_EXH BBTYPE_EXH +#define RPLPOINT_TYPE_SBR BBTYPE_SBR +#define RPLPOINT_TYPE_CALL 3 +#define RPLPOINT_TYPE_INLINE 4 +#define RPLPOINT_TYPE_RETURN 5 +#define RPLPOINT_TYPE_BODY 6 + +#define RPLPOINT_FLAG_NOTRAP 0x01 /* rplpoint cannot be trapped */ +#define RPLPOINT_FLAG_COUNTDOWN 0x02 /* count down hits */ +#define RPLPOINT_FLAG_ACTIVE 0x08 /* trap is active */ + + +#if !defined(NDEBUG) +#define RPLPOINT_CHECK(type) , RPLPOINT_TYPE_##type +#define RPLPOINT_CHECK_BB(bptr) , (bptr)->type +#else +#define RPLPOINT_CHECK(type) +#define RPLPOINT_CHECK_BB(bptr) +#endif + + +/* An `rplpoint` represents a replacement point in a compiled method */ + +struct rplpoint { + u1 *pc; /* machine code PC of this point */ + methodinfo *method; /* source method this point is in */ + rplpoint *parent; /* rplpoint of the inlined body */ /* XXX unify with code */ + rplalloc *regalloc; /* pointer to register index table */ + s4 id; /* id of the rplpoint within method */ + s4 callsize; /* size of call code in bytes */ + unsigned int regalloccount:20; /* number of local allocations */ + unsigned int type:4; /* RPLPOINT_TYPE_... constant */ + unsigned int flags:8; /* OR of RPLPOINT_... constants */ +}; + + +union replace_val_t { + s4 i; + s8 l; + ptrint p; + struct { + u4 lo; + u4 hi; + } words; + float f; + double d; + java_object_t *a; +}; + + +struct sourceframe_t { + sourceframe_t *down; /* source frame down the call chain */ + + methodinfo *method; /* method this frame is in */ + s4 id; + s4 type; + + /* values */ + replace_val_t instance; + + replace_val_t *javastack; /* values of stack vars */ + u1 *javastacktype; /* types of stack vars */ + s4 javastackdepth; /* number of stack vars */ + + replace_val_t *javalocals; /* values of javalocals */ + u1 *javalocaltype; /* types of javalocals */ + s4 javalocalcount; /* number of javalocals */ + + replace_val_t *syncslots; + s4 syncslotcount; /* XXX do we need more than one? */ + + /* mapping info */ + rplpoint *fromrp; /* rplpoint used to read this frame */ + codeinfo *fromcode; /* code this frame was using */ + rplpoint *torp; /* rplpoint this frame was mapped to */ + codeinfo *tocode; /* code this frame was mapped to */ + + /* info for native frames */ + stackframeinfo_t *sfi; /* sfi for native frames, otherwise NULL */ + s4 nativeframesize; /* size (bytes) of native frame */ + u1 *nativepc; + ptrint nativesavint[INT_SAV_CNT]; /* XXX temporary */ + double nativesavflt[FLT_REG_CNT]; /* XXX temporary */ +#if defined(HAS_ADDRESS_REGISTER_FILE) + ptrint nativesavadr[ADR_SAV_CNT]; /* XXX temporary */ +#endif +}; + +#define REPLACE_IS_NATIVE_FRAME(frame) ((frame)->sfi != NULL) +#define REPLACE_IS_JAVA_FRAME(frame) ((frame)->sfi == NULL) + + +struct sourcestate_t { + sourceframe_t *frames; /* list of source frames, from bottom up */ +}; + + +/*** macros for the codegens *******************************************/ + +#define REPLACEMENT_POINTS_INIT(cd, jd) \ + if (!replace_create_replacement_points(jd)) \ + return false; \ + (cd)->replacementpoint = (jd)->code->rplpoints; + +#define REPLACEMENT_POINTS_RESET(cd, jd) \ + (cd)->replacementpoint = (jd)->code->rplpoints; + +#define REPLACEMENT_POINT_BLOCK_START(cd, bptr) \ + if ((bptr)->bitflags & BBFLAG_REPLACEMENT) \ + codegen_set_replacement_point((cd) RPLPOINT_CHECK_BB(bptr)); + +#define REPLACEMENT_POINT_INLINE_START(cd, iptr) \ + codegen_set_replacement_point(cd RPLPOINT_CHECK(INLINE)); + +#define REPLACEMENT_POINT_INLINE_BODY(cd, iptr) \ + codegen_set_replacement_point_notrap(cd RPLPOINT_CHECK(BODY)); + +#define REPLACEMENT_POINT_RETURN(cd, iptr) \ + codegen_set_replacement_point(cd RPLPOINT_CHECK(RETURN)); + +#define REPLACEMENT_POINT_INVOKE(cd, iptr) \ + codegen_set_replacement_point(cd RPLPOINT_CHECK(CALL)); + +#define REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr) \ + if (iptr->opc != ICMD_BUILTIN) \ + cd->replacementpoint[-1].callsize = (cd->mcodeptr - cd->mcodebase)\ + - (ptrint) cd->replacementpoint[-1].pc; + + +/*** macros for the codegens (for GC) **********************************/ + +#if defined(ENABLE_GC_CACAO) + +#define REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr) \ + codegen_set_replacement_point(cd RPLPOINT_CHECK(CALL)); + +#define REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr) \ + if (iptr->opc == ICMD_BUILTIN) \ + cd->replacementpoint[-1].callsize = (cd->mcodeptr - cd->mcodebase)\ + - (ptrint) cd->replacementpoint[-1].pc; + +#else /* defined(ENABLE_GC_CACAO) */ + +#define REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr) +#define REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr) + +#endif /* defined(ENABLE_GC_CACAO) */ + + +/*** prototypes ********************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +bool replace_create_replacement_points(jitdata *jd); +void replace_free_replacement_points(codeinfo *code); + +void replace_activate_replacement_points(codeinfo *code, bool mappable); +void replace_deactivate_replacement_points(codeinfo *code); + +bool replace_me_wrapper(u1 *pc, void *context); + +#if !defined(NDEBUG) +void replace_show_replacement_points(codeinfo *code); +void replace_replacement_point_println(rplpoint *rp, int depth); +void replace_sourcestate_println(sourcestate_t *ss); +void replace_sourcestate_println_short(sourcestate_t *ss); +void replace_source_frame_println(sourceframe_t *frame); +#endif + +/* machine dependent functions (code in ARCH_DIR/md.c) */ + +#if defined(ENABLE_JIT) +void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert); +#endif + +#endif /* defined(ENABLE_REPLACEMENT) */ + +#ifdef __cplusplus +} +#endif + +#endif // _REPLACE_HPP + + +/* + * 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 + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c++ + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */ diff --git a/src/vm/jit/s390/codegen.c b/src/vm/jit/s390/codegen.c index e10a1239a..88b8ad4d4 100644 --- a/src/vm/jit/s390/codegen.c +++ b/src/vm/jit/s390/codegen.c @@ -64,7 +64,7 @@ #include "vm/jit/parse.h" #include "vm/jit/patcher-common.h" #include "vm/jit/reg.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/s390/emit.c b/src/vm/jit/s390/emit.c index e395099dc..25a7d3bb4 100644 --- a/src/vm/jit/s390/emit.c +++ b/src/vm/jit/s390/emit.c @@ -47,7 +47,7 @@ #include "vm/jit/emit-common.h" #include "vm/jit/jit.hpp" #include "vm/jit/patcher-common.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/trace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/sparc64/codegen.c b/src/vm/jit/sparc64/codegen.c index 0712c8c8c..2457cae33 100644 --- a/src/vm/jit/sparc64/codegen.c +++ b/src/vm/jit/sparc64/codegen.c @@ -58,7 +58,7 @@ #include "vm/jit/parse.h" #include "vm/jit/patcher.h" #include "vm/jit/reg.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/sparc64/solaris/macro_rename.h" diff --git a/src/vm/jit/sparc64/emit.c b/src/vm/jit/sparc64/emit.c index 9fc43a4fa..9eedcb329 100644 --- a/src/vm/jit/sparc64/emit.c +++ b/src/vm/jit/sparc64/emit.c @@ -44,7 +44,7 @@ #include "vm/jit/dseg.h" #include "vm/jit/emit-common.h" #include "vm/jit/jit.hpp" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/sparc64/solaris/macro_rename.h" diff --git a/src/vm/jit/stacktrace.hpp b/src/vm/jit/stacktrace.hpp index 376b597be..2d449c3dc 100644 --- a/src/vm/jit/stacktrace.hpp +++ b/src/vm/jit/stacktrace.hpp @@ -132,7 +132,7 @@ u1 *md_get_pv_from_stackframe(u1 *sp); #endif #if defined(ENABLE_INTRP) -u1 *intrp_md_stacktrace_get_returnaddress(u1 *sp, u4 framesize); +void* intrp_md_stacktrace_get_returnaddress(void* sp, int32_t framesize); #endif #if defined(ENABLE_CYCLES_STATS) diff --git a/src/vm/jit/trap.c b/src/vm/jit/trap.c index 0b8b1bca6..c40c5f31d 100644 --- a/src/vm/jit/trap.c +++ b/src/vm/jit/trap.c @@ -47,7 +47,7 @@ #include "vm/jit/jit.hpp" #include "vm/jit/methodtree.h" #include "vm/jit/patcher-common.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" diff --git a/src/vm/jit/x86_64/codegen.c b/src/vm/jit/x86_64/codegen.c index 623978d42..3667689af 100644 --- a/src/vm/jit/x86_64/codegen.c +++ b/src/vm/jit/x86_64/codegen.c @@ -66,7 +66,7 @@ #include "vm/jit/parse.h" #include "vm/jit/patcher-common.h" #include "vm/jit/reg.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.h" diff --git a/src/vm/jit/x86_64/emit.c b/src/vm/jit/x86_64/emit.c index 240be0400..fe9a944d9 100644 --- a/src/vm/jit/x86_64/emit.c +++ b/src/vm/jit/x86_64/emit.c @@ -46,7 +46,7 @@ #include "vm/jit/emit-common.h" #include "vm/jit/jit.hpp" #include "vm/jit/patcher-common.h" -#include "vm/jit/replace.h" +#include "vm/jit/replace.hpp" #include "vm/jit/trace.hpp" #include "vm/jit/trap.h"