1 /* src/vm/jit/replace.c - on-stack replacement of methods
3 Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
36 #if defined(ENABLE_GC_CACAO)
37 # include "mm/cacao-gc/gc.h"
40 #include "mm/memory.h"
42 #include "threads/threads-common.h"
44 #include "toolbox/logging.h"
46 #include "vm/stringlocal.h"
48 #include "vm/jit/abi.h"
49 #include "vm/jit/asmpart.h"
50 #include "vm/jit/disass.h"
51 #include "vm/jit/jit.h"
52 #include "vm/jit/md.h"
53 #include "vm/jit/methodheader.h"
54 #include "vm/jit/replace.h"
55 #include "vm/jit/show.h"
56 #include "vm/jit/stack.h"
58 #include "vmcore/options.h"
59 #include "vmcore/classcache.h"
62 #define REPLACE_PATCH_DYNAMIC_CALL
63 /*#define REPLACE_PATCH_ALL*/
65 #if defined(ENABLE_VMLOG)
66 #include <vmlog_cacao.h>
69 /*** architecture-dependent configuration *************************************/
71 /* first unset the macros (default) */
72 #undef REPLACE_RA_BETWEEN_FRAMES
73 #undef REPLACE_RA_TOP_OF_FRAME
74 #undef REPLACE_RA_LINKAGE_AREA
75 #undef REPLACE_LEAFMETHODS_RA_REGISTER
78 /* i386, x86_64 and m68k */
79 #if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
80 #define REPLACE_RA_BETWEEN_FRAMES
82 #elif defined(__ALPHA__)
83 #define REPLACE_RA_TOP_OF_FRAME
84 #define REPLACE_LEAFMETHODS_RA_REGISTER
85 #define REPLACE_REG_RA REG_RA
87 #elif defined(__POWERPC__)
88 #define REPLACE_RA_LINKAGE_AREA
89 #define REPLACE_LEAFMETHODS_RA_REGISTER
90 #define REPLACE_REG_RA REG_ITMP3 /* the execution state has the LR in itmp3 */
92 #elif defined(__S390__)
93 #define REPLACE_RA_TOP_OF_FRAME
94 #define REPLACE_REG_RA REG_ITMP3
98 /*** configuration of native stack slot size **********************************/
100 /* XXX this should be in md-abi.h files, probably */
102 #if defined(HAS_4BYTE_STACKSLOT)
103 #define SIZE_OF_STACKSLOT 4
104 #define STACK_SLOTS_PER_FLOAT 2
105 typedef u4 stackslot_t;
107 #define SIZE_OF_STACKSLOT 8
108 #define STACK_SLOTS_PER_FLOAT 1
109 typedef u8 stackslot_t;
113 /*** debugging ****************************************************************/
116 static void java_value_print(s4 type, replace_val_t value);
117 static void replace_stackframeinfo_println(stackframeinfo *sfi);
121 #define DOLOG(code) do{ if (opt_TraceReplacement > 1) { code; } } while(0)
122 #define DOLOG_SHORT(code) do{ if (opt_TraceReplacement > 0) { code; } } while(0)
125 #define DOLOG_SHORT(code)
129 /*** statistics ***************************************************************/
131 #define REPLACE_STATISTICS
133 #if defined(REPLACE_STATISTICS)
135 static int stat_replacements = 0;
136 static int stat_frames = 0;
137 static int stat_recompile = 0;
138 static int stat_staticpatch = 0;
139 static int stat_unroll_inline = 0;
140 static int stat_unroll_call = 0;
141 static int stat_dist_frames[20] = { 0 };
142 static int stat_dist_locals[20] = { 0 };
143 static int stat_dist_locals_adr[10] = { 0 };
144 static int stat_dist_locals_prim[10] = { 0 };
145 static int stat_dist_locals_ret[10] = { 0 };
146 static int stat_dist_locals_void[10] = { 0 };
147 static int stat_dist_stack[10] = { 0 };
148 static int stat_dist_stack_adr[10] = { 0 };
149 static int stat_dist_stack_prim[10] = { 0 };
150 static int stat_dist_stack_ret[10] = { 0 };
151 static int stat_methods = 0;
152 static int stat_rploints = 0;
153 static int stat_regallocs = 0;
154 static int stat_dist_method_rplpoints[20] = { 0 };
156 #define REPLACE_COUNT(cnt) (cnt)++
157 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
158 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
160 #define REPLACE_COUNT_DIST(array, val) \
162 int limit = (sizeof(array) / sizeof(int)) - 1; \
163 if ((val) < (limit)) (array)[val]++; \
164 else (array)[limit]++; \
167 static void replace_statistics_source_frame(sourceframe_t *frame);
171 #define REPLACE_COUNT(cnt)
172 #define REPLACE_COUNT_IF(cnt, cond)
173 #define REPLACE_COUNT_INC(cnt, inc)
174 #define REPLACE_COUNT_DIST(array, val)
176 #endif /* defined(REPLACE_STATISTICS) */
179 /*** constants used internally ************************************************/
181 #define TOP_IS_NORMAL 0
182 #define TOP_IS_ON_STACK 1
183 #define TOP_IS_IN_ITMP1 2
184 #define TOP_IS_VOID 3
187 /******************************************************************************/
188 /* PART I: Creating / freeing replacement points */
189 /******************************************************************************/
192 /* replace_create_replacement_point ********************************************
194 Create a replacement point.
197 jd...............current jitdata
198 iinfo............inlining info for the current position
199 rp...............pre-allocated (uninitialized) rplpoint
200 type.............RPLPOINT_TYPE constant
201 iptr.............current instruction
202 *pra.............current rplalloc pointer
203 javalocals.......the javalocals at the current point
204 stackvars........the stack variables at the current point
205 stackdepth.......the stack depth at the current point
206 paramcount.......number of parameters at the start of stackvars
209 *rpa.............points to the next free rplalloc
211 *******************************************************************************/
213 static void replace_create_replacement_point(jitdata *jd,
214 insinfo_inline *iinfo,
231 REPLACE_COUNT(stat_rploints);
233 rp->method = (iinfo) ? iinfo->method : jd->m;
234 rp->pc = NULL; /* set by codegen */
235 rp->callsize = 0; /* set by codegen */
239 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
241 /* XXX unify these two fields */
242 rp->parent = (iinfo) ? iinfo->rp : NULL;
244 /* store local allocation info of javalocals */
247 for (i = 0; i < rp->method->maxlocals; ++i) {
248 index = javalocals[i];
255 ra->flags = v->flags & (INMEMORY);
256 ra->regoff = v->vv.regoff;
260 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
268 /* store allocation info of java stack vars */
270 for (i = 0; i < stackdepth; ++i) {
271 v = VAR(stackvars[i]);
272 ra->flags = v->flags & (INMEMORY);
273 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
275 /* XXX how to handle locals on the stack containing returnAddresses? */
276 if (v->type == TYPE_RET) {
277 assert(stackvars[i] >= jd->localcount);
278 ra->regoff = v->vv.retaddr->nr;
281 ra->regoff = v->vv.regoff;
285 /* total number of allocations */
287 rp->regalloccount = ra - rp->regalloc;
293 /* replace_create_inline_start_replacement_point *******************************
295 Create an INLINE_START replacement point.
298 jd...............current jitdata
299 rp...............pre-allocated (uninitialized) rplpoint
300 iptr.............current instruction
301 *pra.............current rplalloc pointer
302 javalocals.......the javalocals at the current point
305 *rpa.............points to the next free rplalloc
308 the insinfo_inline * for the following inlined body
310 *******************************************************************************/
312 static insinfo_inline * replace_create_inline_start_replacement_point(
319 insinfo_inline *calleeinfo;
322 calleeinfo = iptr->sx.s23.s3.inlineinfo;
326 replace_create_replacement_point(jd, calleeinfo->parent, rp,
327 RPLPOINT_TYPE_INLINE, iptr, pra,
329 calleeinfo->stackvars, calleeinfo->stackvarscount,
330 calleeinfo->paramcount);
332 if (calleeinfo->synclocal != UNUSED) {
334 ra->index = RPLALLOC_SYNC;
335 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
336 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
346 /* replace_create_replacement_points *******************************************
348 Create the replacement points for the given code.
351 jd...............current jitdata, must not have any replacement points
354 code->rplpoints.......set to the list of replacement points
355 code->rplpointcount...number of replacement points
356 code->regalloc........list of allocation info
357 code->regalloccount...total length of allocation info list
358 code->globalcount.....number of global allocations at the
359 start of code->regalloc
362 true.............everything ok
363 false............an exception has been thrown
365 *******************************************************************************/
367 #define CLEAR_javalocals(array, method) \
369 for (i=0; i<(method)->maxlocals; ++i) \
370 (array)[i] = UNUSED; \
373 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
375 if ((array) != NULL) \
376 MCOPY((dest), (array), s4, (method)->maxlocals); \
378 CLEAR_javalocals((dest), (method)); \
381 #define COUNT_javalocals(array, method, counter) \
383 for (i=0; i<(method)->maxlocals; ++i) \
384 if ((array)[i] != UNUSED) \
388 bool replace_create_replacement_points(jitdata *jd)
406 insinfo_inline *iinfo;
409 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
413 REPLACE_COUNT(stat_methods);
415 /* get required compiler data */
420 /* assert that we wont overwrite already allocated data */
424 assert(code->rplpoints == NULL);
425 assert(code->rplpointcount == 0);
426 assert(code->regalloc == NULL);
427 assert(code->regalloccount == 0);
428 assert(code->globalcount == 0);
432 /* set codeinfo flags */
434 if (jd->isleafmethod)
435 code_flag_leafmethod(code);
437 /* in instance methods, we may need a rplpoint at the method entry */
439 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
440 if (!(m->flags & ACC_STATIC)) {
441 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
447 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
449 /* iterate over the basic block list to find replacement points */
454 javalocals = DMNEW(s4, jd->maxlocals);
456 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
460 if (bptr->flags < BBFINISHED)
463 /* get info about this block */
466 iinfo = bptr->inlineinfo;
468 /* initialize javalocals at the start of this block */
470 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
472 /* iterate over the instructions */
475 iend = iptr + bptr->icount;
479 for (; iptr != iend; ++iptr) {
481 #if defined(ENABLE_GC_CACAO)
483 md = iptr->sx.s23.s3.bte->md;
485 COUNT_javalocals(javalocals, m, alloccount);
486 alloccount += iptr->s1.argcount;
488 alloccount -= iinfo->throughcount;
492 case ICMD_INVOKESTATIC:
493 case ICMD_INVOKESPECIAL:
494 case ICMD_INVOKEVIRTUAL:
495 case ICMD_INVOKEINTERFACE:
496 INSTRUCTION_GET_METHODDESC(iptr, md);
498 COUNT_javalocals(javalocals, m, alloccount);
499 alloccount += iptr->s1.argcount;
501 alloccount -= iinfo->throughcount;
509 stack_javalocals_store(iptr, javalocals);
523 case ICMD_INLINE_START:
524 iinfo = iptr->sx.s23.s3.inlineinfo;
527 COUNT_javalocals(javalocals, m, alloccount);
528 alloccount += iinfo->stackvarscount;
529 if (iinfo->synclocal != UNUSED)
533 /* javalocals may be set at next block start, or now */
534 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
537 case ICMD_INLINE_BODY:
538 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
540 jl = iinfo->javalocals_start;
542 /* get the javalocals from the following block start */
544 jl = bptr->next->javalocals;
547 COUNT_javalocals(jl, m, alloccount);
550 case ICMD_INLINE_END:
551 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
552 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
553 iinfo = iptr->sx.s23.s3.inlineinfo;
555 if (iinfo->javalocals_end)
556 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
557 iinfo = iinfo->parent;
561 if (iptr == bptr->iinstr)
563 } /* end instruction loop */
565 /* create replacement points at targets of backward branches */
566 /* We only need the replacement point there, if there is no */
567 /* replacement point inside the block. */
569 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
570 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
571 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
575 if (test > startcount) {
576 /* we don't need an extra rplpoint */
577 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
581 alloccount += bptr->indepth;
582 if (bptr->inlineinfo)
583 alloccount -= bptr->inlineinfo->throughcount;
585 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
589 } /* end basicblock loop */
591 /* if no points were found, there's nothing to do */
596 /* allocate replacement point array and allocation array */
598 rplpoints = MNEW(rplpoint, count);
599 regalloc = MNEW(rplalloc, alloccount);
602 /* initialize replacement point structs */
606 /* XXX try to share code with the counting loop! */
608 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
611 if (bptr->flags < BBFINISHED)
614 /* get info about this block */
617 iinfo = bptr->inlineinfo;
619 /* initialize javalocals at the start of this block */
621 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
623 /* create replacement points at targets of backward branches */
625 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
627 i = (iinfo) ? iinfo->throughcount : 0;
628 replace_create_replacement_point(jd, iinfo, rp++,
629 bptr->type, bptr->iinstr, &ra,
630 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
632 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
633 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
636 /* iterate over the instructions */
639 iend = iptr + bptr->icount;
641 for (; iptr != iend; ++iptr) {
643 #if defined(ENABLE_GC_CACAO)
645 md = iptr->sx.s23.s3.bte->md;
647 i = (iinfo) ? iinfo->throughcount : 0;
648 replace_create_replacement_point(jd, iinfo, rp++,
649 RPLPOINT_TYPE_CALL, iptr, &ra,
650 javalocals, iptr->sx.s23.s2.args,
651 iptr->s1.argcount - i,
656 case ICMD_INVOKESTATIC:
657 case ICMD_INVOKESPECIAL:
658 case ICMD_INVOKEVIRTUAL:
659 case ICMD_INVOKEINTERFACE:
660 INSTRUCTION_GET_METHODDESC(iptr, md);
662 i = (iinfo) ? iinfo->throughcount : 0;
663 replace_create_replacement_point(jd, iinfo, rp++,
664 RPLPOINT_TYPE_CALL, iptr, &ra,
665 javalocals, iptr->sx.s23.s2.args,
666 iptr->s1.argcount - i,
675 stack_javalocals_store(iptr, javalocals);
683 replace_create_replacement_point(jd, iinfo, rp++,
684 RPLPOINT_TYPE_RETURN, iptr, &ra,
685 NULL, &(iptr->s1.varindex), 1, 0);
689 replace_create_replacement_point(jd, iinfo, rp++,
690 RPLPOINT_TYPE_RETURN, iptr, &ra,
694 case ICMD_INLINE_START:
695 iinfo = replace_create_inline_start_replacement_point(
696 jd, rp++, iptr, &ra, javalocals);
698 /* javalocals may be set at next block start, or now */
699 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
702 case ICMD_INLINE_BODY:
703 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
705 jl = iinfo->javalocals_start;
707 /* get the javalocals from the following block start */
709 jl = bptr->next->javalocals;
711 /* create a non-trappable rplpoint */
712 replace_create_replacement_point(jd, iinfo, rp++,
713 RPLPOINT_TYPE_BODY, iptr, &ra,
715 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
718 case ICMD_INLINE_END:
719 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
720 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
721 iinfo = iptr->sx.s23.s3.inlineinfo;
723 if (iinfo->javalocals_end)
724 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
725 iinfo = iinfo->parent;
728 } /* end instruction loop */
729 } /* end basicblock loop */
731 assert((rp - rplpoints) == count);
732 assert((ra - regalloc) == alloccount);
734 /* store the data in the codeinfo */
736 code->rplpoints = rplpoints;
737 code->rplpointcount = count;
738 code->regalloc = regalloc;
739 code->regalloccount = alloccount;
740 code->globalcount = 0;
741 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
742 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
743 #if defined(HAS_ADDRESS_REGISTER_FILE)
744 code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
746 code->memuse = rd->memuse;
747 code->stackframesize = jd->cd->stackframesize;
749 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
750 REPLACE_COUNT_INC(stat_regallocs, alloccount);
752 /* everything alright */
758 /* replace_free_replacement_points *********************************************
760 Free memory used by replacement points.
763 code.............codeinfo whose replacement points should be freed.
765 *******************************************************************************/
767 void replace_free_replacement_points(codeinfo *code)
772 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
775 MFREE(code->regalloc,rplalloc,code->regalloccount);
777 code->rplpoints = NULL;
778 code->rplpointcount = 0;
779 code->regalloc = NULL;
780 code->regalloccount = 0;
781 code->globalcount = 0;
785 /******************************************************************************/
786 /* PART II: Activating / deactivating replacement points */
787 /******************************************************************************/
790 /* replace_activate_replacement_points *****************************************
792 Activate the replacement points of the given compilation unit. When this
793 function returns, the replacement points are "armed", so each thread
794 reaching one of the points will enter the replacement mechanism.
797 code.............codeinfo of which replacement points should be
799 mappable.........if true, only mappable replacement points are
802 *******************************************************************************/
804 void replace_activate_replacement_points(codeinfo *code, bool mappable)
811 assert(code->savedmcode == NULL);
813 /* count trappable replacement points */
816 i = code->rplpointcount;
817 rp = code->rplpoints;
819 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
822 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
828 /* allocate buffer for saved machine code */
830 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
831 code->savedmcode = savedmcode;
832 savedmcode += count * REPLACEMENT_PATCH_SIZE;
834 /* activate trappable replacement points */
835 /* (in reverse order to handle overlapping points within basic blocks) */
837 i = code->rplpointcount;
838 rp = code->rplpoints + i;
840 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
842 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
845 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
848 DOLOG( printf("activate replacement point:\n");
849 replace_replacement_point_println(rp, 1); fflush(stdout); );
851 savedmcode -= REPLACEMENT_PATCH_SIZE;
853 #if defined(ENABLE_JIT)
854 # if defined(ENABLE_DISASSEMBLER)
855 DOLOG( printf("\tinstruction before: ");
856 disassinstr(rp->pc); fflush(stdout); );
859 md_patch_replacement_point(rp->pc, savedmcode, false);
861 # if defined(ENABLE_DISASSEMBLER)
862 DOLOG( printf("\tinstruction after : ");
863 disassinstr(rp->pc); fflush(stdout); );
867 rp->flags |= RPLPOINT_FLAG_ACTIVE;
870 assert(savedmcode == code->savedmcode);
874 /* replace_deactivate_replacement_points ***************************************
876 Deactivate a replacement points in the given compilation unit.
877 When this function returns, the replacement points will be "un-armed",
878 that is a each thread reaching a point will just continue normally.
881 code.............the compilation unit
883 *******************************************************************************/
885 void replace_deactivate_replacement_points(codeinfo *code)
892 if (code->savedmcode == NULL) {
893 /* disarm countdown points by patching the branches */
895 i = code->rplpointcount;
896 rp = code->rplpoints;
898 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
899 == RPLPOINT_FLAG_COUNTDOWN)
902 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
909 assert(code->savedmcode != NULL);
910 savedmcode = code->savedmcode;
912 /* de-activate each trappable replacement point */
914 i = code->rplpointcount;
915 rp = code->rplpoints;
918 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
923 DOLOG( printf("deactivate replacement point:\n");
924 replace_replacement_point_println(rp, 1); fflush(stdout); );
926 #if defined(ENABLE_JIT)
927 # if defined(ENABLE_DISASSEMBLER)
928 DOLOG( printf("\tinstruction before: ");
929 disassinstr(rp->pc); fflush(stdout); );
932 md_patch_replacement_point(rp->pc, savedmcode, true);
934 # if defined(ENABLE_DISASSEMBLER)
935 DOLOG( printf("\tinstruction before: ");
936 disassinstr(rp->pc); fflush(stdout); );
940 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
942 savedmcode += REPLACEMENT_PATCH_SIZE;
945 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
947 /* free saved machine code */
949 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
950 code->savedmcode = NULL;
954 /******************************************************************************/
955 /* PART III: The replacement mechanism */
956 /******************************************************************************/
959 /* replace_read_value **********************************************************
961 Read a value with the given allocation from the execution state.
964 es...............execution state
965 ra...............allocation
966 javaval..........where to put the value
969 *javaval.........the value
971 *******************************************************************************/
973 static void replace_read_value(executionstate_t *es,
975 replace_val_t *javaval)
977 if (ra->flags & INMEMORY) {
978 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
979 #ifdef HAS_4BYTE_STACKSLOT
980 if (IS_2_WORD_TYPE(ra->type)) {
981 javaval->l = *(u8*)(es->sp + ra->regoff);
985 javaval->p = *(ptrint*)(es->sp + ra->regoff);
986 #ifdef HAS_4BYTE_STACKSLOT
991 /* allocated register */
992 if (IS_FLT_DBL_TYPE(ra->type)) {
993 javaval->d = es->fltregs[ra->regoff];
995 if (ra->type == TYPE_FLT)
996 javaval->f = javaval->d;
998 #if defined(HAS_ADDRESS_REGISTER_FILE)
999 else if (IS_ADR_TYPE(ra->type)) {
1000 javaval->p = es->adrregs[ra->regoff];
1004 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1005 if (ra->type == TYPE_LNG) {
1006 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
1007 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
1010 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
1011 javaval->p = es->intregs[ra->regoff];
1017 /* replace_write_value *********************************************************
1019 Write a value to the given allocation in the execution state.
1022 es...............execution state
1023 ra...............allocation
1024 *javaval.........the value
1026 *******************************************************************************/
1028 static void replace_write_value(executionstate_t *es,
1030 replace_val_t *javaval)
1032 if (ra->flags & INMEMORY) {
1033 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1034 #ifdef HAS_4BYTE_STACKSLOT
1035 if (IS_2_WORD_TYPE(ra->type)) {
1036 *(u8*)(es->sp + ra->regoff) = javaval->l;
1040 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1041 #ifdef HAS_4BYTE_STACKSLOT
1046 /* allocated register */
1049 es->fltregs[ra->regoff] = (double) javaval->f;
1052 es->fltregs[ra->regoff] = javaval->d;
1054 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1056 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1057 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1060 #if defined(HAS_ADDRESS_REGISTER_FILE)
1062 es->adrregs[ra->regoff] = javaval->p;
1065 es->intregs[ra->regoff] = javaval->p;
1071 /* replace_new_sourceframe *****************************************************
1073 Allocate a new source frame and insert it at the front of the frame list.
1076 ss...............the source state
1079 ss->frames.......set to new frame (the new head of the frame list).
1082 returns the new frame
1084 *******************************************************************************/
1086 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1088 sourceframe_t *frame;
1090 frame = DNEW(sourceframe_t);
1091 MZERO(frame, sourceframe_t, 1);
1093 frame->down = ss->frames;
1100 /* replace_read_executionstate *************************************************
1102 Read a source frame from the given executions state.
1103 The new source frame is pushed to the front of the frame list of the
1107 rp...............replacement point at which `es` was taken
1108 es...............execution state
1109 ss...............the source state to add the source frame to
1110 topframe.........true, if the first (top-most) source frame on the
1114 *ss..............the source state with the newly created source frame
1117 *******************************************************************************/
1119 static s4 replace_normalize_type_map[] = {
1120 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1121 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1122 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1123 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1124 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1125 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1126 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1130 static void replace_read_executionstate(rplpoint *rp,
1131 executionstate_t *es,
1140 sourceframe_t *frame;
1143 stackslot_t *basesp;
1145 code = code_find_codeinfo_for_pc(rp->pc);
1147 topslot = TOP_IS_NORMAL;
1151 sp = (stackslot_t *) es->sp;
1153 /* in some cases the top stack slot is passed in REG_ITMP1 */
1155 if (rp->type == BBTYPE_EXH) {
1156 topslot = TOP_IS_IN_ITMP1;
1159 /* calculate base stack pointer */
1161 basesp = sp + code->stackframesize;
1163 /* create the source frame */
1165 frame = replace_new_sourceframe(ss);
1166 frame->method = rp->method;
1168 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1169 frame->type = replace_normalize_type_map[rp->type];
1171 frame->fromcode = code;
1173 /* read local variables */
1175 count = m->maxlocals;
1176 frame->javalocalcount = count;
1177 frame->javalocals = DMNEW(replace_val_t, count);
1178 frame->javalocaltype = DMNEW(u1, count);
1180 /* mark values as undefined */
1181 for (i=0; i<count; ++i) {
1182 #if !defined(NDEBUG)
1183 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1185 frame->javalocaltype[i] = TYPE_VOID;
1188 /* some entries in the intregs array are not meaningful */
1189 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1190 #if !defined(NDEBUG)
1191 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1193 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1195 #endif /* !defined(NDEBUG) */
1197 /* read javalocals */
1199 count = rp->regalloccount;
1202 while (count && (i = ra->index) >= 0) {
1203 assert(i < m->maxlocals);
1204 frame->javalocaltype[i] = ra->type;
1205 if (ra->type == TYPE_RET)
1206 frame->javalocals[i].i = ra->regoff;
1208 replace_read_value(es, ra, frame->javalocals + i);
1213 /* read instance, if this is the first rplpoint */
1215 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1216 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1218 /* we are at the start of the method body, so if local 0 is set, */
1219 /* it is the instance. */
1220 if (frame->javalocaltype[0] == TYPE_ADR)
1221 frame->instance = frame->javalocals[0];
1226 md = rp->method->parseddesc;
1228 assert(md->paramcount >= 1);
1229 instra.type = TYPE_ADR;
1230 instra.regoff = md->params[0].regoff;
1231 if (md->params[0].inmemory) {
1232 instra.flags = INMEMORY;
1233 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1238 replace_read_value(es, &instra, &(frame->instance));
1241 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1243 /* read stack slots */
1245 frame->javastackdepth = count;
1246 frame->javastack = DMNEW(replace_val_t, count);
1247 frame->javastacktype = DMNEW(u1, count);
1249 #if !defined(NDEBUG)
1250 /* mark values as undefined */
1251 for (i=0; i<count; ++i) {
1252 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1253 frame->javastacktype[i] = TYPE_VOID;
1255 #endif /* !defined(NDEBUG) */
1259 /* the first stack slot is special in SBR and EXH blocks */
1261 if (topslot == TOP_IS_ON_STACK) {
1264 assert(ra->index == RPLALLOC_STACK);
1265 assert(ra->type == TYPE_ADR);
1266 frame->javastack[i].p = sp[-1];
1267 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1272 else if (topslot == TOP_IS_IN_ITMP1) {
1275 assert(ra->index == RPLALLOC_STACK);
1276 assert(ra->type == TYPE_ADR);
1277 frame->javastack[i].p = es->intregs[REG_ITMP1];
1278 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1283 else if (topslot == TOP_IS_VOID) {
1286 assert(ra->index == RPLALLOC_STACK);
1287 frame->javastack[i].l = 0;
1288 frame->javastacktype[i] = TYPE_VOID;
1294 /* read remaining stack slots */
1296 for (; count--; ra++) {
1297 if (ra->index == RPLALLOC_SYNC) {
1298 assert(rp->type == RPLPOINT_TYPE_INLINE);
1300 /* only read synchronization slots when traversing an inline point */
1303 sourceframe_t *calleeframe = frame->down;
1304 assert(calleeframe);
1305 assert(calleeframe->syncslotcount == 0);
1306 assert(calleeframe->syncslots == NULL);
1308 calleeframe->syncslotcount = 1;
1309 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1310 replace_read_value(es,ra,calleeframe->syncslots);
1313 frame->javastackdepth--;
1317 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1319 /* do not read parameters of calls down the call chain */
1321 if (!topframe && ra->index == RPLALLOC_PARAM) {
1322 frame->javastackdepth--;
1325 if (ra->type == TYPE_RET)
1326 frame->javastack[i].i = ra->regoff;
1328 replace_read_value(es,ra,frame->javastack + i);
1329 frame->javastacktype[i] = ra->type;
1336 /* replace_write_executionstate ************************************************
1338 Pop a source frame from the front of the frame list of the given source state
1339 and write its values into the execution state.
1342 rp...............replacement point for which execution state should be
1344 es...............the execution state to modify
1345 ss...............the given source state
1346 topframe.........true, if this is the last (top-most) source frame to be
1350 *es..............the execution state derived from the source state
1352 *******************************************************************************/
1354 static void replace_write_executionstate(rplpoint *rp,
1355 executionstate_t *es,
1364 sourceframe_t *frame;
1367 stackslot_t *basesp;
1369 code = code_find_codeinfo_for_pc(rp->pc);
1371 topslot = TOP_IS_NORMAL;
1373 /* pop a source frame */
1377 ss->frames = frame->down;
1379 /* calculate stack pointer */
1381 sp = (stackslot_t *) es->sp;
1383 basesp = sp + code->stackframesize;
1385 /* in some cases the top stack slot is passed in REG_ITMP1 */
1387 if (rp->type == BBTYPE_EXH) {
1388 topslot = TOP_IS_IN_ITMP1;
1391 /* write javalocals */
1394 count = rp->regalloccount;
1396 while (count && (i = ra->index) >= 0) {
1397 assert(i < m->maxlocals);
1398 assert(i < frame->javalocalcount);
1399 assert(ra->type == frame->javalocaltype[i]);
1400 if (ra->type == TYPE_RET) {
1401 /* XXX assert that it matches this rplpoint */
1404 replace_write_value(es, ra, frame->javalocals + i);
1409 /* write stack slots */
1413 /* the first stack slot is special in SBR and EXH blocks */
1415 if (topslot == TOP_IS_ON_STACK) {
1418 assert(ra->index == RPLALLOC_STACK);
1419 assert(i < frame->javastackdepth);
1420 assert(frame->javastacktype[i] == TYPE_ADR);
1421 sp[-1] = frame->javastack[i].p;
1426 else if (topslot == TOP_IS_IN_ITMP1) {
1429 assert(ra->index == RPLALLOC_STACK);
1430 assert(i < frame->javastackdepth);
1431 assert(frame->javastacktype[i] == TYPE_ADR);
1432 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1437 else if (topslot == TOP_IS_VOID) {
1440 assert(ra->index == RPLALLOC_STACK);
1441 assert(i < frame->javastackdepth);
1442 assert(frame->javastacktype[i] == TYPE_VOID);
1448 /* write remaining stack slots */
1450 for (; count--; ra++) {
1451 if (ra->index == RPLALLOC_SYNC) {
1452 assert(rp->type == RPLPOINT_TYPE_INLINE);
1454 /* only write synchronization slots when traversing an inline point */
1457 assert(frame->down);
1458 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1459 assert(frame->down->syncslots != NULL);
1461 replace_write_value(es,ra,frame->down->syncslots);
1466 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1468 /* do not write parameters of calls down the call chain */
1470 if (!topframe && ra->index == RPLALLOC_PARAM) {
1474 assert(i < frame->javastackdepth);
1475 assert(ra->type == frame->javastacktype[i]);
1476 if (ra->type == TYPE_RET) {
1477 /* XXX assert that it matches this rplpoint */
1480 replace_write_value(es,ra,frame->javastack + i);
1492 /* replace_pop_activation_record ***********************************************
1494 Peel a stack frame from the execution state.
1496 *** This function imitates the effects of the method epilog ***
1497 *** and returning from the method call. ***
1500 es...............execution state
1501 frame............source frame, receives synchronization slots
1504 *es..............the execution state after popping the stack frame
1506 *******************************************************************************/
1508 u1* replace_pop_activation_record(executionstate_t *es,
1509 sourceframe_t *frame)
1517 stackslot_t *basesp;
1523 /* read the return address */
1525 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1526 if (code_is_leafmethod(es->code))
1527 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1530 ra = md_stacktrace_get_returnaddress(es->sp,
1531 SIZE_OF_STACKSLOT * es->code->stackframesize);
1533 DOLOG( printf("return address: %p\n", (void*)ra); );
1537 /* calculate the base of the stack frame */
1539 sp = (stackslot_t *) es->sp;
1540 basesp = sp + es->code->stackframesize;
1542 /* read slots used for synchronization */
1544 assert(frame->syncslotcount == 0);
1545 assert(frame->syncslots == NULL);
1546 count = code_get_sync_slot_count(es->code);
1547 frame->syncslotcount = count;
1548 frame->syncslots = DMNEW(replace_val_t, count);
1549 for (i=0; i<count; ++i) {
1550 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1553 /* restore return address, if part of frame */
1555 #if defined(REPLACE_RA_TOP_OF_FRAME)
1556 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1557 if (!code_is_leafmethod(es->code))
1559 es->intregs[REPLACE_REG_RA] = *--basesp;
1560 #endif /* REPLACE_RA_TOP_OF_FRAME */
1562 #if defined(REPLACE_RA_LINKAGE_AREA)
1563 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1564 if (!code_is_leafmethod(es->code))
1566 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1567 #endif /* REPLACE_RA_LINKAGE_AREA */
1569 /* restore saved int registers */
1572 for (i=0; i<es->code->savedintcount; ++i) {
1573 while (nregdescint[--reg] != REG_SAV)
1575 es->intregs[reg] = *--basesp;
1578 /* restore saved flt registers */
1582 for (i=0; i<es->code->savedfltcount; ++i) {
1583 while (nregdescfloat[--reg] != REG_SAV)
1585 basesp -= STACK_SLOTS_PER_FLOAT;
1586 es->fltregs[reg] = *(double*)basesp;
1589 #if defined(HAS_ADDRESS_REGISTER_FILE)
1590 /* restore saved adr registers */
1593 for (i=0; i<es->code->savedadrcount; ++i) {
1594 while (nregdescadr[--reg] != REG_SAV)
1596 es->adrregs[reg] = *--basesp;
1600 /* adjust the stackpointer */
1602 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1604 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1605 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1608 /* Set the new pc. Subtract one so we do not hit the replacement point */
1609 /* of the instruction following the call, if there is one. */
1613 /* find the new codeinfo */
1615 pv = md_codegen_get_pv_from_pc(ra);
1617 DOLOG( printf("PV = %p\n", (void*) pv); );
1619 if (pv == NULL) /* XXX can this really happen? */
1622 code = *(codeinfo **)(pv + CodeinfoPointer);
1624 DOLOG( printf("CODE = %p\n", (void*) code); );
1626 /* return NULL if we reached native code */
1631 /* in debugging mode clobber non-saved registers */
1633 #if !defined(NDEBUG)
1635 for (i=0; i<INT_REG_CNT; ++i)
1636 if ((nregdescint[i] != REG_SAV)
1638 && (i != REPLACE_REG_RA)
1641 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1642 for (i=0; i<FLT_REG_CNT; ++i)
1643 if (nregdescfloat[i] != REG_SAV)
1644 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1645 # if defined(HAS_ADDRESS_REGISTER_FILE)
1646 for (i=0; i<ADR_REG_CNT; ++i)
1647 if (nregdescadr[i] != REG_SAV)
1648 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1650 #endif /* !defined(NDEBUG) */
1652 return (code) ? ra : NULL;
1656 /* replace_patch_method_pointer ************************************************
1658 Patch a method pointer (may be in code, data segment, vftbl, or interface
1662 mpp..............address of the method pointer to patch
1663 entrypoint.......the new entrypoint of the method
1664 kind.............kind of call to patch, used only for debugging
1666 *******************************************************************************/
1668 static void replace_patch_method_pointer(methodptr *mpp,
1669 methodptr entrypoint,
1672 #if !defined(NDEBUG)
1677 DOLOG( printf("patch method pointer from: %p to %p\n",
1678 (void*) *mpp, (void*)entrypoint); );
1680 #if !defined(NDEBUG)
1681 oldcode = *(codeinfo **)((u1*)(*mpp) + CodeinfoPointer);
1682 newcode = *(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer);
1684 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1685 method_println(oldcode->m);
1686 printf("\t with %p ", (void*) newcode);
1687 method_println(newcode->m); );
1689 assert(oldcode->m == newcode->m);
1692 /* write the new entrypoint */
1694 *mpp = (methodptr) entrypoint;
1698 /* replace_patch_class *********************************************************
1700 Patch a method in the given class.
1703 vftbl............vftbl of the class
1704 m................the method to patch
1705 oldentrypoint....the old entrypoint to replace
1706 entrypoint.......the new entrypoint
1708 *******************************************************************************/
1710 void replace_patch_class(vftbl_t *vftbl,
1719 /* patch the vftbl of the class */
1721 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1725 /* patch the interface tables */
1727 assert(oldentrypoint);
1729 for (i=0; i < vftbl->interfacetablelength; ++i) {
1730 mpp = vftbl->interfacetable[-i];
1731 mppend = mpp + vftbl->interfacevftbllength[i];
1732 for (; mpp != mppend; ++mpp)
1733 if (*mpp == oldentrypoint) {
1734 replace_patch_method_pointer(mpp, entrypoint, "interface");
1740 /* replace_patch_class_hierarchy ***********************************************
1742 Patch a method in all loaded classes.
1745 m................the method to patch
1746 oldentrypoint....the old entrypoint to replace
1747 entrypoint.......the new entrypoint
1749 *******************************************************************************/
1751 struct replace_patch_data_t {
1757 #define CODEINFO_OF_CODE(entrypoint) \
1758 (*(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer))
1760 #define METHOD_OF_CODE(entrypoint) \
1761 (CODEINFO_OF_CODE(entrypoint)->m)
1763 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1765 vftbl_t *vftbl = c->vftbl;
1768 && vftbl->vftbllength > pd->m->vftblindex
1769 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1770 && METHOD_OF_CODE(vftbl->table[pd->m->vftblindex]) == pd->m)
1772 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1776 void replace_patch_class_hierarchy(methodinfo *m,
1780 struct replace_patch_data_t pd;
1783 pd.oldentrypoint = oldentrypoint;
1784 pd.entrypoint = entrypoint;
1786 DOLOG_SHORT( printf("patching class hierarchy: ");
1787 method_println(m); );
1789 classcache_foreach_loaded_class(
1790 (classcache_foreach_functionptr_t) &replace_patch_callback,
1795 /* replace_patch_future_calls **************************************************
1797 Analyse a call site and depending on the kind of call patch the call, the
1798 virtual function table, or the interface table.
1801 ra...............return address pointing after the call site
1802 callerframe......source frame of the caller
1803 calleeframe......source frame of the callee, must have been mapped
1805 *******************************************************************************/
1807 void replace_patch_future_calls(u1 *ra,
1808 sourceframe_t *callerframe,
1809 sourceframe_t *calleeframe)
1812 methodptr entrypoint;
1813 methodptr oldentrypoint;
1816 codeinfo *calleecode;
1817 methodinfo *calleem;
1822 assert(callerframe->down == calleeframe);
1824 /* get the new codeinfo and the method that shall be entered */
1826 calleecode = calleeframe->tocode;
1829 calleem = calleeframe->method;
1830 assert(calleem == calleecode->m);
1832 entrypoint = (methodptr) calleecode->entrypoint;
1834 /* check if we are at an method entry rplpoint at the innermost frame */
1836 atentry = (calleeframe->down == NULL)
1837 && !(calleem->flags & ACC_STATIC)
1838 && (calleeframe->fromrp->id == 0); /* XXX */
1840 /* get the position to patch, in case it was a statically bound call */
1842 pv = callerframe->fromcode->entrypoint;
1843 patchpos = md_jit_method_patch_address(pv, ra, NULL);
1845 if (patchpos == NULL) {
1846 /* the call was dispatched dynamically */
1848 /* we can only patch such calls if we are at the entry point */
1853 assert((calleem->flags & ACC_STATIC) == 0);
1855 oldentrypoint = calleeframe->fromcode->entrypoint;
1857 /* we need to know the instance */
1859 if (!calleeframe->instance.a) {
1860 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1861 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1867 obj = calleeframe->instance.a;
1870 assert(vftbl->class->vftbl == vftbl);
1872 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1874 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1877 /* the call was statically bound */
1879 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1884 /* replace_push_activation_record **********************************************
1886 Push a stack frame onto the execution state.
1888 *** This function imitates the effects of a call and the ***
1889 *** method prolog of the callee. ***
1892 es...............execution state
1893 rpcall...........the replacement point at the call site
1894 callerframe......source frame of the caller, or NULL for creating the
1896 calleeframe......source frame of the callee, must have been mapped
1899 *es..............the execution state after pushing the stack frame
1901 *******************************************************************************/
1903 void replace_push_activation_record(executionstate_t *es,
1905 sourceframe_t *callerframe,
1906 sourceframe_t *calleeframe)
1911 stackslot_t *basesp;
1914 codeinfo *calleecode;
1917 assert(!rpcall || callerframe);
1918 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1919 assert(!rpcall || rpcall == callerframe->torp);
1920 assert(calleeframe);
1921 assert(!callerframe || calleeframe == callerframe->down);
1923 /* the compilation unit we are entering */
1925 calleecode = calleeframe->tocode;
1928 /* calculate the return address */
1931 ra = rpcall->pc + rpcall->callsize;
1933 ra = es->pc + 1 /* XXX this is ugly */;
1935 /* write the return address */
1937 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1938 es->sp -= SIZE_OF_STACKSLOT;
1940 *((stackslot_t *)es->sp) = (stackslot_t) ra;
1941 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1943 #if defined(REPLACE_REG_RA)
1944 es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1947 /* we move into a new code unit */
1949 es->code = calleecode;
1951 /* set the new pc XXX not needed? */
1953 es->pc = calleecode->entrypoint;
1955 /* build the stackframe */
1957 DOLOG( printf("building stackframe of %d words at %p\n",
1958 calleecode->stackframesize, (void*)es->sp); );
1960 sp = (stackslot_t *) es->sp;
1963 sp -= calleecode->stackframesize;
1966 /* in debug mode, invalidate stack frame first */
1968 /* XXX may not invalidate linkage area used by native code! */
1969 #if !defined(NDEBUG) && 0
1970 for (i=0; i<(basesp - sp); ++i) {
1971 sp[i] = 0xdeaddeadU;
1975 /* save the return address register */
1977 #if defined(REPLACE_RA_TOP_OF_FRAME)
1978 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1979 if (!code_is_leafmethod(calleecode))
1981 *--basesp = (ptrint) ra;
1982 #endif /* REPLACE_RA_TOP_OF_FRAME */
1984 #if defined(REPLACE_RA_LINKAGE_AREA)
1985 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1986 if (!code_is_leafmethod(calleecode))
1988 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1989 #endif /* REPLACE_RA_LINKAGE_AREA */
1991 /* save int registers */
1994 for (i=0; i<calleecode->savedintcount; ++i) {
1995 while (nregdescint[--reg] != REG_SAV)
1997 *--basesp = es->intregs[reg];
1999 /* XXX may not clobber saved regs used by native code! */
2000 #if !defined(NDEBUG) && 0
2001 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
2005 /* save flt registers */
2009 for (i=0; i<calleecode->savedfltcount; ++i) {
2010 while (nregdescfloat[--reg] != REG_SAV)
2012 basesp -= STACK_SLOTS_PER_FLOAT;
2013 *(double*)basesp = es->fltregs[reg];
2015 /* XXX may not clobber saved regs used by native code! */
2016 #if !defined(NDEBUG) && 0
2017 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
2021 #if defined(HAS_ADDRESS_REGISTER_FILE)
2022 /* save adr registers */
2025 for (i=0; i<calleecode->savedadrcount; ++i) {
2026 while (nregdescadr[--reg] != REG_SAV)
2028 *--basesp = es->adrregs[reg];
2030 /* XXX may not clobber saved regs used by native code! */
2031 #if !defined(NDEBUG) && 0
2032 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
2037 /* write slots used for synchronization */
2039 count = code_get_sync_slot_count(calleecode);
2040 assert(count == calleeframe->syncslotcount);
2041 for (i=0; i<count; ++i) {
2042 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2047 es->pv = calleecode->entrypoint;
2049 /* redirect future invocations */
2051 if (callerframe && rpcall) {
2052 #if defined(REPLACE_PATCH_ALL)
2053 if (rpcall->type == callerframe->fromrp->type)
2055 if (rpcall == callerframe->fromrp)
2057 replace_patch_future_calls(ra, callerframe, calleeframe);
2062 /* replace_find_replacement_point **********************************************
2064 Find the replacement point in the given code corresponding to the
2065 position given in the source frame.
2068 code.............the codeinfo in which to search the rplpoint
2069 frame............the source frame defining the position to look for
2070 parent...........parent replacement point to match
2073 the replacement point
2075 *******************************************************************************/
2077 rplpoint * replace_find_replacement_point(codeinfo *code,
2078 sourceframe_t *frame,
2091 DOLOG( printf("searching replacement point for:\n");
2092 replace_source_frame_println(frame); );
2096 DOLOG( printf("code = %p\n", (void*)code); );
2098 rp = code->rplpoints;
2099 i = code->rplpointcount;
2101 if (rp->id == frame->id && rp->method == frame->method
2102 && rp->parent == parent
2103 && replace_normalize_type_map[rp->type] == frame->type)
2105 /* check if returnAddresses match */
2106 /* XXX optimize: only do this if JSRs in method */
2107 DOLOG( printf("checking match for:");
2108 replace_replacement_point_println(rp, 1); fflush(stdout); );
2111 for (j = rp->regalloccount; j--; ++ra) {
2112 if (ra->type == TYPE_RET) {
2113 if (ra->index == RPLALLOC_STACK) {
2114 assert(stacki < frame->javastackdepth);
2115 if (frame->javastack[stacki].i != ra->regoff)
2120 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2121 if (frame->javalocals[ra->index].i != ra->regoff)
2134 #if !defined(NDEBUG)
2135 printf("candidate replacement points were:\n");
2136 rp = code->rplpoints;
2137 i = code->rplpointcount;
2139 replace_replacement_point_println(rp, 1);
2143 vm_abort("no matching replacement point found");
2144 return NULL; /* NOT REACHED */
2148 /* replace_find_replacement_point_for_pc ***************************************
2150 Find the nearest replacement point at or before the given PC. The
2151 given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
2152 the replacement point to be found.
2155 code.............compilation unit the PC is in
2156 pc...............the machine code PC
2159 the replacement point found, or
2160 NULL if no replacement point was found
2162 *******************************************************************************/
2164 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2170 DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
2171 method_println(code->m); );
2175 rp = code->rplpoints;
2176 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2177 DOLOG( replace_replacement_point_println(rp, 2); );
2178 if (rp->pc <= pc && rp->pc + rp->callsize >= pc)
2186 /* replace_pop_native_frame ****************************************************
2188 Unroll a native frame in the execution state and create a source frame
2192 es...............current execution state
2193 ss...............the current source state
2194 sfi..............stackframeinfo for the native frame
2197 es...............execution state after unrolling the native frame
2198 ss...............gets the added native source frame
2200 *******************************************************************************/
2202 static void replace_pop_native_frame(executionstate_t *es,
2204 stackframeinfo *sfi)
2206 sourceframe_t *frame;
2212 frame = replace_new_sourceframe(ss);
2216 /* remember pc and size of native frame */
2218 frame->nativepc = es->pc;
2219 frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2220 assert(frame->nativeframesize >= 0);
2222 /* remember values of saved registers */
2225 for (i=0; i<INT_REG_CNT; ++i) {
2226 if (nregdescint[i] == REG_SAV)
2227 frame->nativesavint[j++] = es->intregs[i];
2231 for (i=0; i<FLT_REG_CNT; ++i) {
2232 if (nregdescfloat[i] == REG_SAV)
2233 frame->nativesavflt[j++] = es->fltregs[i];
2236 #if defined(HAS_ADDRESS_REGISTER_FILE)
2238 for (i=0; i<ADR_REG_CNT; ++i) {
2239 if (nregdescadr[i] == REG_SAV)
2240 frame->nativesavadr[j++] = es->adrregs[i];
2244 /* restore saved registers */
2246 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2248 for (i=0; i<INT_REG_CNT; ++i) {
2249 if (nregdescint[i] == REG_SAV)
2250 es->intregs[i] = sfi->intregs[j++];
2253 /* XXX we don't have them, yet, in the sfi, so clear them */
2255 for (i=0; i<INT_REG_CNT; ++i) {
2256 if (nregdescint[i] == REG_SAV)
2261 /* XXX we don't have float registers in the sfi, so clear them */
2263 for (i=0; i<FLT_REG_CNT; ++i) {
2264 if (nregdescfloat[i] == REG_SAV)
2265 es->fltregs[i] = 0.0;
2268 #if defined(HAS_ADDRESS_REGISTER_FILE)
2269 # if defined(ENABLE_GC_CACAO)
2271 for (i=0; i<ADR_REG_CNT; ++i) {
2272 if (nregdescadr[i] == REG_SAV)
2273 es->adrregs[i] = sfi->adrregs[j++];
2276 for (i=0; i<ADR_REG_CNT; ++i) {
2277 if (nregdescadr[i] == REG_SAV)
2283 /* restore pv, pc, and sp */
2285 if (sfi->pv == NULL) {
2286 /* frame of a native function call */
2287 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2292 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2295 /* find the new codeinfo */
2297 DOLOG( printf("PV = %p\n", (void*) es->pv); );
2299 assert(es->pv != NULL);
2301 code = *(codeinfo **)(es->pv + CodeinfoPointer);
2303 DOLOG( printf("CODE = %p\n", (void*) code); );
2309 /* replace_push_native_frame ***************************************************
2311 Rebuild a native frame onto the execution state and remove its source frame.
2313 Note: The native frame is "rebuild" by setting fields like PC and stack
2314 pointer in the execution state accordingly. Values in the
2315 stackframeinfo may be modified, but the actual stack frame of the
2316 native code is not touched.
2319 es...............current execution state
2320 ss...............the current source state
2323 es...............execution state after re-rolling the native frame
2324 ss...............the native source frame is removed
2326 *******************************************************************************/
2328 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2330 sourceframe_t *frame;
2336 DOLOG( printf("pushing native frame\n"); );
2338 /* remove the frame from the source state */
2342 assert(REPLACE_IS_NATIVE_FRAME(frame));
2344 ss->frames = frame->down;
2346 /* assert that the native frame has not moved */
2348 assert(es->sp == frame->sfi->sp);
2350 /* update saved registers in the stackframeinfo */
2352 #if defined(ENABLE_GC_CACAO)
2354 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2355 for (i=0; i<INT_REG_CNT; ++i) {
2356 if (nregdescint[i] == REG_SAV)
2357 frame->sfi->intregs[j++] = es->intregs[i];
2360 for (i=0; i<ADR_REG_CNT; ++i) {
2361 if (nregdescadr[i] == REG_SAV)
2362 frame->sfi->adrregs[j++] = es->adrregs[i];
2366 /* XXX leave float registers untouched here */
2369 /* restore saved registers */
2372 for (i=0; i<INT_REG_CNT; ++i) {
2373 if (nregdescint[i] == REG_SAV)
2374 es->intregs[i] = frame->nativesavint[j++];
2378 for (i=0; i<FLT_REG_CNT; ++i) {
2379 if (nregdescfloat[i] == REG_SAV)
2380 es->fltregs[i] = frame->nativesavflt[j++];
2383 #if defined(HAS_ADDRESS_REGISTER_FILE)
2385 for (i=0; i<ADR_REG_CNT; ++i) {
2386 if (nregdescadr[i] == REG_SAV)
2387 es->adrregs[i] = frame->nativesavadr[j++];
2391 /* skip the native frame on the machine stack */
2393 es->sp -= frame->nativeframesize;
2395 /* set the pc the next frame must return to */
2397 es->pc = frame->nativepc;
2401 /* replace_recover_source_state ************************************************
2403 Recover the source state from the given replacement point and execution
2407 rp...............replacement point that has been reached, if any
2408 sfi..............stackframeinfo, if called from native code
2409 es...............execution state at the replacement point rp
2414 *******************************************************************************/
2416 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2417 stackframeinfo *sfi,
2418 executionstate_t *es)
2423 #if defined(REPLACE_STATISTICS)
2427 /* create the source frame structure in dump memory */
2429 ss = DNEW(sourcestate_t);
2432 /* each iteration of the loop recovers one source frame */
2439 DOLOG( replace_executionstate_println(es); );
2441 /* if we are not at a replacement point, it is a native frame */
2444 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2447 replace_pop_native_frame(es, ss, sfi);
2450 if (es->code == NULL)
2453 goto after_machine_frame;
2456 /* read the values for this source frame from the execution state */
2458 DOLOG( printf("recovering source state for%s:\n",
2459 (ss->frames == NULL) ? " TOPFRAME" : "");
2460 replace_replacement_point_println(rp, 1); );
2462 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2464 #if defined(ENABLE_VMLOG)
2465 vmlog_cacao_unrol_method(ss->frames->method);
2468 #if defined(REPLACE_STATISTICS)
2469 REPLACE_COUNT(stat_frames);
2471 replace_statistics_source_frame(ss->frames);
2474 /* in locked areas (below native frames), identity map the frame */
2477 ss->frames->torp = ss->frames->fromrp;
2478 ss->frames->tocode = ss->frames->fromcode;
2481 /* unroll to the next (outer) frame */
2484 /* this frame is in inlined code */
2486 DOLOG( printf("INLINED!\n"); );
2490 assert(rp->type == RPLPOINT_TYPE_INLINE);
2491 REPLACE_COUNT(stat_unroll_inline);
2494 /* this frame had been called at machine-level. pop it. */
2496 DOLOG( printf("UNWIND\n"); );
2498 ra = replace_pop_activation_record(es, ss->frames);
2500 DOLOG( printf("REACHED NATIVE CODE\n"); );
2504 #if !defined(ENABLE_GC_CACAO)
2505 break; /* XXX remove to activate native frames */
2510 /* find the replacement point at the call site */
2512 after_machine_frame:
2513 rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2516 vm_abort("could not find replacement point while unrolling call");
2518 DOLOG( printf("found replacement point.\n");
2519 replace_replacement_point_println(rp, 1); );
2521 assert(rp->type == RPLPOINT_TYPE_CALL);
2522 REPLACE_COUNT(stat_unroll_call);
2524 } /* end loop over source frames */
2526 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2532 /* replace_map_source_state ****************************************************
2534 Map each source frame in the given source state to a target replacement
2535 point and compilation unit. If no valid code is available for a source
2536 frame, it is (re)compiled.
2539 ss...............the source state
2542 ss...............the source state, modified: The `torp` and `tocode`
2543 fields of each source frame are set.
2546 true.............everything went ok
2547 false............an exception has been thrown
2549 *******************************************************************************/
2551 static bool replace_map_source_state(sourcestate_t *ss)
2553 sourceframe_t *frame;
2556 rplpoint *parent; /* parent of inlined rplpoint */
2557 #if defined(REPLACE_STATISTICS)
2564 /* iterate over the source frames from outermost to innermost */
2566 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2568 /* XXX skip native frames */
2570 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2575 /* map frames which are not already mapped */
2577 if (frame->tocode) {
2578 code = frame->tocode;
2583 assert(frame->torp == NULL);
2585 if (parent == NULL) {
2586 /* find code for this frame */
2588 #if defined(REPLACE_STATISTICS)
2589 oldcode = frame->method->code;
2591 /* request optimization of hot methods and their callers */
2593 if (frame->method->hitcountdown < 0
2594 || (frame->down && frame->down->method->hitcountdown < 0))
2595 jit_request_optimization(frame->method);
2597 code = jit_get_current_code(frame->method);
2600 return false; /* exception */
2602 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2607 /* map this frame */
2609 rp = replace_find_replacement_point(code, frame, parent);
2611 frame->tocode = code;
2615 if (rp->type == RPLPOINT_TYPE_CALL) {
2628 /* replace_map_source_state_identity *******************************************
2630 Map each source frame in the given source state to the same replacement
2631 point and compilation unit it was derived from. This is mainly used for
2635 ss...............the source state
2638 ss...............the source state, modified: The `torp` and `tocode`
2639 fields of each source frame are set.
2641 *******************************************************************************/
2643 #if defined(ENABLE_GC_CACAO)
2644 static void replace_map_source_state_identity(sourcestate_t *ss)
2646 sourceframe_t *frame;
2648 /* iterate over the source frames from outermost to innermost */
2650 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2652 /* skip native frames */
2654 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2658 /* map frames using the identity mapping */
2660 if (frame->tocode) {
2661 assert(frame->tocode == frame->fromcode);
2662 assert(frame->torp == frame->fromrp);
2664 assert(frame->tocode == NULL);
2665 assert(frame->torp == NULL);
2666 frame->tocode = frame->fromcode;
2667 frame->torp = frame->fromrp;
2674 /* replace_build_execution_state ***********************************************
2676 Build an execution state for the given (mapped) source state.
2678 !!! CAUTION: This function rewrites the machine stack !!!
2680 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2683 ss...............the source state. Must have been mapped by
2684 replace_map_source_state before.
2685 es...............the base execution state on which to build
2688 *es..............the new execution state
2690 *******************************************************************************/
2692 static void replace_build_execution_state(sourcestate_t *ss,
2693 executionstate_t *es)
2696 sourceframe_t *prevframe;
2703 while (ss->frames) {
2705 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2706 prevframe = ss->frames;
2707 replace_push_native_frame(es, ss);
2713 if (parent == NULL) {
2714 /* create a machine-level stack frame */
2716 DOLOG( printf("pushing activation record for:\n");
2717 if (rp) replace_replacement_point_println(rp, 1);
2718 else printf("\tfirst frame\n"); );
2720 replace_push_activation_record(es, rp, prevframe, ss->frames);
2722 DOLOG( replace_executionstate_println(es); );
2725 rp = ss->frames->torp;
2728 DOLOG( printf("creating execution state for%s:\n",
2729 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2730 replace_replacement_point_println(ss->frames->fromrp, 1);
2731 replace_replacement_point_println(rp, 1); );
2733 es->code = ss->frames->tocode;
2734 prevframe = ss->frames;
2736 #if defined(ENABLE_VMLOG)
2737 vmlog_cacao_rerol_method(ss->frames->method);
2740 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2742 DOLOG( replace_executionstate_println(es); );
2744 if (rp->type == RPLPOINT_TYPE_CALL) {
2755 /* replace_me ******************************************************************
2757 This function is called by the signal handler when a thread reaches
2758 a replacement point. `replace_me` must map the execution state to the
2759 target replacement point and let execution continue there.
2761 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2764 rp...............replacement point that has been reached
2765 es...............execution state read by signal handler
2767 *******************************************************************************/
2769 static void replace_me(rplpoint *rp, executionstate_t *es)
2771 stackframeinfo *sfi;
2773 sourceframe_t *frame;
2777 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2778 threadobject *thread;
2781 origcode = es->code;
2784 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2785 stat_replacements, (void*)THREADOBJECT,
2787 method_println(es->code->m); );
2789 DOLOG( replace_replacement_point_println(rp, 1); );
2791 REPLACE_COUNT(stat_replacements);
2793 /* mark start of dump memory area */
2795 dumpsize = dump_size();
2797 /* get the stackframeinfo for the current thread */
2799 sfi = STACKFRAMEINFO;
2801 /* recover source state */
2803 ss = replace_recover_source_state(rp, sfi, es);
2805 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2806 /* if there is a collection pending, we assume the replacement point should
2807 suspend this thread */
2811 thread = THREADOBJECT;
2813 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2815 /* map the sourcestate using the identity mapping */
2816 replace_map_source_state_identity(ss);
2818 /* since we enter the same method again, we turn off rps now */
2819 /* XXX michi: can we really do this? what if the rp was active before
2820 we activated it for the gc? */
2821 replace_deactivate_replacement_points(origcode);
2823 /* remember executionstate and sourcestate for this thread */
2824 GC_EXECUTIONSTATE = es;
2825 GC_SOURCESTATE = ss;
2827 /* really suspend this thread now (PC = 0) */
2828 threads_suspend_ack(NULL, NULL);
2830 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2833 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2835 /* map the source state */
2837 if (!replace_map_source_state(ss))
2838 vm_abort("exception during method replacement");
2840 DOLOG( replace_sourcestate_println(ss); );
2842 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2844 #if !defined(NDEBUG)
2845 /* avoid infinite loops by self-replacement, only if not in testing mode */
2847 if (!opt_TestReplacement) {
2850 frame = frame->down;
2852 if (frame->torp == origrp) {
2854 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2856 replace_deactivate_replacement_points(origcode);
2861 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2865 /* build the new execution state */
2867 replace_build_execution_state(ss, es);
2869 #if !defined(NDEBUG)
2870 /* continue execution after patched machine code, if testing mode enabled */
2872 if (opt_TestReplacement)
2873 es->pc += REPLACEMENT_PATCH_SIZE;
2876 /* release dump area */
2878 dump_release(dumpsize);
2882 /* replace_me_wrapper **********************************************************
2884 This function is called by the signal handler. It determines if there
2885 is an active replacement point pending at the given PC and returns
2888 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2891 pc...............the program counter that triggered the replacement.
2892 context..........the context (machine state) to which the
2893 replacement should be applied.
2896 context..........the context after replacement finished.
2899 true.............replacement done, everything went ok
2900 false............no replacement done, context unchanged
2902 *******************************************************************************/
2904 bool replace_me_wrapper(u1 *pc, void *context)
2908 executionstate_t es;
2910 /* search the codeinfo for the given PC */
2912 code = code_find_codeinfo_for_pc(pc);
2915 /* search for a replacement point at the given PC */
2917 rp = replace_find_replacement_point_for_pc(code, pc);
2919 /* check if the replacement point belongs to given PC and is active */
2921 if ((rp != NULL) && (rp->pc == pc) && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
2923 /* set codeinfo pointer in execution state */
2927 /* read execution state from current context */
2929 md_replace_executionstate_read(&es, context);
2931 DOLOG( printf("REPLACEMENT READ: ");
2932 replace_executionstate_println(&es); );
2934 /* do the actual replacement */
2936 replace_me(rp, &es);
2938 /* write execution state to current context */
2940 md_replace_executionstate_write(&es, context);
2942 DOLOG( printf("REPLACEMENT WRITE: ");
2943 replace_executionstate_println(&es); );
2945 /* new code is entered after returning */
2947 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2955 /******************************************************************************/
2956 /* NOTE: Stuff specific to the exact GC is below. */
2957 /******************************************************************************/
2959 #if defined(ENABLE_GC_CACAO)
2960 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
2962 stackframeinfo *sfi;
2963 executionstate_t *es;
2966 /* get the stackframeinfo of this thread */
2967 assert(thread == THREADOBJECT);
2968 sfi = STACKFRAMEINFO;
2970 /* create the execution state */
2971 es = DNEW(executionstate_t);
2974 es->pv = 0; /* since we are in a native, PV is invalid! */
2975 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
2977 /* we assume we are in a native (no replacement point)! */
2978 ss = replace_recover_source_state(NULL, sfi, es);
2980 /* map the sourcestate using the identity mapping */
2981 replace_map_source_state_identity(ss);
2983 /* remember executionstate and sourcestate for this thread */
2984 GC_EXECUTIONSTATE = es;
2985 GC_SOURCESTATE = ss;
2989 #if defined(ENABLE_GC_CACAO)
2990 void replace_gc_into_native(threadobject *thread)
2992 executionstate_t *es;
2995 /* get the executionstate and sourcestate for the given thread */
2996 es = GC_EXECUTIONSTATE;
2997 ss = GC_SOURCESTATE;
2999 /* rebuild the stack of the given thread */
3000 replace_build_execution_state(ss, es);
3005 /******************************************************************************/
3006 /* NOTE: No important code below. */
3007 /******************************************************************************/
3010 /* statistics *****************************************************************/
3012 #if defined(REPLACE_STATISTICS)
3013 static void print_freq(FILE *file,int *array,int limit)
3018 for (i=0; i<limit; ++i)
3020 sum += array[limit];
3021 for (i=0; i<limit; ++i) {
3023 fprintf(file," %3d: %8d (cum %3d%%)\n",
3024 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3026 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3028 #endif /* defined(REPLACE_STATISTICS) */
3031 #if defined(REPLACE_STATISTICS)
3033 #define REPLACE_PRINT_DIST(name, array) \
3034 printf(" " name " distribution:\n"); \
3035 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3037 void replace_print_statistics(void)
3039 printf("replacement statistics:\n");
3040 printf(" # of replacements: %d\n", stat_replacements);
3041 printf(" # of frames: %d\n", stat_frames);
3042 printf(" # of recompilations: %d\n", stat_recompile);
3043 printf(" patched static calls:%d\n", stat_staticpatch);
3044 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3045 printf(" unrolled calls: %d\n", stat_unroll_call);
3046 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3047 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3048 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3049 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3050 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3051 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3052 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3053 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3054 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3055 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3057 printf(" # of methods: %d\n", stat_methods);
3058 printf(" # of replacement points: %d\n", stat_rploints);
3059 printf(" # of regallocs: %d\n", stat_regallocs);
3060 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3061 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3062 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3066 #endif /* defined(REPLACE_STATISTICS) */
3069 #if defined(REPLACE_STATISTICS)
3070 static void replace_statistics_source_frame(sourceframe_t *frame)
3079 for (i=0; i<frame->javalocalcount; ++i) {
3080 switch (frame->javalocaltype[i]) {
3081 case TYPE_ADR: adr++; break;
3082 case TYPE_RET: ret++; break;
3083 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3084 case TYPE_VOID: vd++; break;
3089 REPLACE_COUNT_DIST(stat_dist_locals, n);
3090 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3091 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3092 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3093 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3094 adr = ret = prim = n = 0;
3095 for (i=0; i<frame->javastackdepth; ++i) {
3096 switch (frame->javastacktype[i]) {
3097 case TYPE_ADR: adr++; break;
3098 case TYPE_RET: ret++; break;
3099 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3103 REPLACE_COUNT_DIST(stat_dist_stack, n);
3104 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3105 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3106 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3108 #endif /* defined(REPLACE_STATISTICS) */
3111 /* debugging helpers **********************************************************/
3113 /* replace_replacement_point_println *******************************************
3115 Print replacement point info.
3118 rp...............the replacement point to print
3120 *******************************************************************************/
3122 #if !defined(NDEBUG)
3124 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3126 static char *replace_type_str[] = {
3136 void replace_replacement_point_println(rplpoint *rp, int depth)
3142 printf("(rplpoint *)NULL\n");
3146 for (j=0; j<depth; ++j)
3149 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3150 rp->id, (void*)rp,rp->pc,rp->callsize,
3151 replace_type_str[rp->type]);
3152 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3154 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3155 printf(" COUNTDOWN");
3156 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3158 printf(" parent:%p\n", (void*)rp->parent);
3159 for (j=0; j<depth; ++j)
3161 printf("ra:%d = [", rp->regalloccount);
3163 for (j=0; j<rp->regalloccount; ++j) {
3166 index = rp->regalloc[j].index;
3168 case RPLALLOC_STACK: printf("S"); break;
3169 case RPLALLOC_PARAM: printf("P"); break;
3170 case RPLALLOC_SYNC : printf("Y"); break;
3171 default: printf("%d", index);
3173 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3174 if (rp->regalloc[j].type == TYPE_RET) {
3175 printf("ret(L%03d)", rp->regalloc[j].regoff);
3178 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3183 for (j=0; j<depth; ++j)
3186 method_print(rp->method);
3190 #endif /* !defined(NDEBUG) */
3193 /* replace_show_replacement_points *********************************************
3195 Print replacement point info.
3198 code.............codeinfo whose replacement points should be printed.
3200 *******************************************************************************/
3202 #if !defined(NDEBUG)
3203 void replace_show_replacement_points(codeinfo *code)
3211 printf("(codeinfo *)NULL\n");
3215 printf("\treplacement points: %d\n",code->rplpointcount);
3217 printf("\ttotal allocations : %d\n",code->regalloccount);
3218 printf("\tsaved int regs : %d\n",code->savedintcount);
3219 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3220 #if defined(HAS_ADDRESS_REGISTER_FILE)
3221 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3223 printf("\tmemuse : %d\n",code->memuse);
3227 for (i=0; i<code->rplpointcount; ++i) {
3228 rp = code->rplpoints + i;
3231 parent = rp->parent;
3234 parent = parent->parent;
3236 replace_replacement_point_println(rp, depth);
3242 /* replace_executionstate_println **********************************************
3244 Print execution state
3247 es...............the execution state to print
3249 *******************************************************************************/
3251 #if !defined(NDEBUG)
3252 void replace_executionstate_println(executionstate_t *es)
3260 printf("(executionstate_t *)NULL\n");
3264 printf("executionstate_t:\n");
3265 printf("\tpc = %p",(void*)es->pc);
3266 printf(" sp = %p",(void*)es->sp);
3267 printf(" pv = %p\n",(void*)es->pv);
3268 #if defined(ENABLE_DISASSEMBLER)
3269 for (i=0; i<INT_REG_CNT; ++i) {
3274 #if SIZEOF_VOID_P == 8
3275 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3277 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3282 for (i=0; i<FLT_REG_CNT; ++i) {
3287 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3291 # if defined(HAS_ADDRESS_REGISTER_FILE)
3292 for (i=0; i<ADR_REG_CNT; ++i) {
3297 printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
3304 sp = (stackslot_t *) es->sp;
3309 methoddesc *md = es->code->m->parseddesc;
3310 slots = es->code->stackframesize;
3311 extraslots = 1 + md->memuse;
3318 printf("\tstack slots(+%d) at sp:", extraslots);
3319 for (i=0; i<slots+extraslots; ++i) {
3322 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3323 #ifdef HAS_4BYTE_STACKSLOT
3324 printf("%08lx",(unsigned long)*sp++);
3326 printf("%016llx",(unsigned long long)*sp++);
3328 printf("%c", (i >= slots) ? ')' : ' ');
3333 printf("\tcode: %p", (void*)es->code);
3334 if (es->code != NULL) {
3335 printf(" stackframesize=%d ", es->code->stackframesize);
3336 method_print(es->code->m);
3344 #if !defined(NDEBUG)
3345 static void java_value_print(s4 type, replace_val_t value)
3350 printf("%016llx",(unsigned long long) value.l);
3352 if (type < 0 || type > TYPE_RET)
3353 printf(" <INVALID TYPE:%d>", type);
3355 printf(" %s", show_jit_type_names[type]);
3357 if (type == TYPE_ADR && value.a != NULL) {
3360 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3362 if (obj->vftbl->class == class_java_lang_String) {
3364 u = javastring_toutf(obj, false);
3365 utf_display_printable_ascii(u);
3369 else if (type == TYPE_INT) {
3370 printf(" %ld", (long) value.i);
3372 else if (type == TYPE_LNG) {
3373 printf(" %lld", (long long) value.l);
3375 else if (type == TYPE_FLT) {
3376 printf(" %f", value.f);
3378 else if (type == TYPE_DBL) {
3379 printf(" %f", value.d);
3382 #endif /* !defined(NDEBUG) */
3385 #if !defined(NDEBUG)
3386 void replace_source_frame_println(sourceframe_t *frame)
3391 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3392 printf("\tNATIVE\n");
3393 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3394 printf("\tnativepc: %p\n", frame->nativepc);
3395 printf("\tframesize: %d\n", frame->nativeframesize);
3398 for (i=0; i<INT_REG_CNT; ++i) {
3399 if (nregdescint[i] == REG_SAV)
3400 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3404 for (i=0; i<FLT_REG_CNT; ++i) {
3405 if (nregdescfloat[i] == REG_SAV)
3406 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3414 method_println(frame->method);
3415 printf("\tid: %d\n", frame->id);
3416 printf("\ttype: %s\n", replace_type_str[frame->type]);
3419 if (frame->instance.a) {
3420 printf("\tinstance: ");
3421 java_value_print(TYPE_ADR, frame->instance);
3425 if (frame->javalocalcount) {
3426 printf("\tlocals (%d):\n",frame->javalocalcount);
3427 for (i=0; i<frame->javalocalcount; ++i) {
3428 t = frame->javalocaltype[i];
3429 if (t == TYPE_VOID) {
3430 printf("\tlocal[ %2d] = void\n",i);
3433 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3434 java_value_print(t, frame->javalocals[i]);
3441 if (frame->javastackdepth) {
3442 printf("\tstack (depth %d):\n",frame->javastackdepth);
3443 for (i=0; i<frame->javastackdepth; ++i) {
3444 t = frame->javastacktype[i];
3445 if (t == TYPE_VOID) {
3446 printf("\tstack[%2d] = void", i);
3449 printf("\tstack[%2d] = ",i);
3450 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3457 if (frame->syncslotcount) {
3458 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3459 for (i=0; i<frame->syncslotcount; ++i) {
3460 printf("\tslot[%2d] = ",i);
3461 #ifdef HAS_4BYTE_STACKSLOT
3462 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3464 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3470 if (frame->fromcode) {
3471 printf("\tfrom %p ", (void*)frame->fromcode);
3472 method_println(frame->fromcode->m);
3474 if (frame->tocode) {
3475 printf("\tto %p ", (void*)frame->tocode);
3476 method_println(frame->tocode->m);
3479 if (frame->fromrp) {
3480 printf("\tfrom replacement point:\n");
3481 replace_replacement_point_println(frame->fromrp, 2);
3484 printf("\tto replacement point:\n");
3485 replace_replacement_point_println(frame->torp, 2);
3490 #endif /* !defined(NDEBUG) */
3493 /* replace_sourcestate_println *************************************************
3498 ss...............the source state to print
3500 *******************************************************************************/
3502 #if !defined(NDEBUG)
3503 void replace_sourcestate_println(sourcestate_t *ss)
3506 sourceframe_t *frame;
3509 printf("(sourcestate_t *)NULL\n");
3513 printf("sourcestate_t:\n");
3515 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3516 printf(" frame %d:\n", i);
3517 replace_source_frame_println(frame);
3523 /* replace_sourcestate_println_short *******************************************
3525 Print a compact representation of the given source state.
3528 ss...............the source state to print
3530 *******************************************************************************/
3532 #if !defined(NDEBUG)
3533 void replace_sourcestate_println_short(sourcestate_t *ss)
3535 sourceframe_t *frame;
3537 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3540 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3541 printf("NATIVE (pc %p size %d) ",
3542 (void*)frame->nativepc, frame->nativeframesize);
3543 replace_stackframeinfo_println(frame->sfi);
3548 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3551 printf("%s", replace_type_str[frame->fromrp->type]);
3553 if (frame->torp && frame->torp->type != frame->fromrp->type)
3554 printf("->%s", replace_type_str[frame->torp->type]);
3556 if (frame->tocode != frame->fromcode)
3557 printf(" (%p->%p/%d) ",
3558 (void*) frame->fromcode, (void*) frame->tocode,
3561 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3563 method_println(frame->method);
3568 #if !defined(NDEBUG)
3569 static void replace_stackframeinfo_println(stackframeinfo *sfi)
3571 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3572 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3573 (void*)sfi->ra, (void*)sfi->xpc);
3576 method_println(sfi->method);
3583 * These are local overrides for various environment variables in Emacs.
3584 * Please do not remove this and leave it at the end of the file, where
3585 * Emacs will automagically detect them.
3586 * ---------------------------------------------------------------------
3589 * indent-tabs-mode: t
3593 * vim:noexpandtab:sw=4:ts=4: