1 /* src/vm/jit/replace.c - on-stack replacement of methods
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
35 #if defined(ENABLE_GC_CACAO)
36 # include "mm/cacao-gc/gc.h"
39 #include "mm/memory.h"
41 #include "threads/threads-common.h"
43 #include "toolbox/logging.h"
45 #include "vm/stringlocal.h"
47 #include "vm/jit/abi.h"
48 #include "vm/jit/asmpart.h"
49 #include "vm/jit/disass.h"
50 #include "vm/jit/jit.h"
51 #include "vm/jit/methodheader.h"
52 #include "vm/jit/replace.h"
53 #include "vm/jit/show.h"
54 #include "vm/jit/stack.h"
56 #include "vmcore/options.h"
57 #include "vmcore/classcache.h"
60 #define REPLACE_PATCH_DYNAMIC_CALL
61 /*#define REPLACE_PATCH_ALL*/
63 #if defined(ENABLE_VMLOG)
64 #include <vmlog_cacao.h>
67 /*** architecture-dependent configuration *************************************/
69 /* first unset the macros (default) */
70 #undef REPLACE_RA_BETWEEN_FRAMES
71 #undef REPLACE_RA_TOP_OF_FRAME
72 #undef REPLACE_RA_LINKAGE_AREA
73 #undef REPLACE_LEAFMETHODS_RA_REGISTER
76 /* i386, x86_64 and m68k */
77 #if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
78 #define REPLACE_RA_BETWEEN_FRAMES
80 #elif defined(__ALPHA__)
81 #define REPLACE_RA_TOP_OF_FRAME
82 #define REPLACE_LEAFMETHODS_RA_REGISTER
83 #define REPLACE_REG_RA REG_RA
85 #elif defined(__POWERPC__)
86 #define REPLACE_RA_LINKAGE_AREA
87 #define REPLACE_LEAFMETHODS_RA_REGISTER
88 #define REPLACE_REG_RA REG_ITMP3 /* the execution state has the LR in itmp3 */
90 #elif defined(__S390__)
91 #define REPLACE_RA_TOP_OF_FRAME
92 #define REPLACE_REG_RA REG_ITMP3
96 /*** configuration of native stack slot size **********************************/
98 /* XXX this should be in md-abi.h files, probably */
100 #if defined(HAS_4BYTE_STACKSLOT)
101 #define SIZE_OF_STACKSLOT 4
102 #define STACK_SLOTS_PER_FLOAT 2
103 typedef u4 stackslot_t;
105 #define SIZE_OF_STACKSLOT 8
106 #define STACK_SLOTS_PER_FLOAT 1
107 typedef u8 stackslot_t;
111 /*** debugging ****************************************************************/
114 static void java_value_print(s4 type, replace_val_t value);
115 static void replace_stackframeinfo_println(stackframeinfo_t *sfi);
119 #define DOLOG(code) do{ if (opt_TraceReplacement > 1) { code; } } while(0)
120 #define DOLOG_SHORT(code) do{ if (opt_TraceReplacement > 0) { code; } } while(0)
123 #define DOLOG_SHORT(code)
127 /*** statistics ***************************************************************/
129 #define REPLACE_STATISTICS
131 #if defined(REPLACE_STATISTICS)
133 static int stat_replacements = 0;
134 static int stat_frames = 0;
135 static int stat_recompile = 0;
136 static int stat_staticpatch = 0;
137 static int stat_unroll_inline = 0;
138 static int stat_unroll_call = 0;
139 static int stat_dist_frames[20] = { 0 };
140 static int stat_dist_locals[20] = { 0 };
141 static int stat_dist_locals_adr[10] = { 0 };
142 static int stat_dist_locals_prim[10] = { 0 };
143 static int stat_dist_locals_ret[10] = { 0 };
144 static int stat_dist_locals_void[10] = { 0 };
145 static int stat_dist_stack[10] = { 0 };
146 static int stat_dist_stack_adr[10] = { 0 };
147 static int stat_dist_stack_prim[10] = { 0 };
148 static int stat_dist_stack_ret[10] = { 0 };
149 static int stat_methods = 0;
150 static int stat_rploints = 0;
151 static int stat_regallocs = 0;
152 static int stat_dist_method_rplpoints[20] = { 0 };
154 #define REPLACE_COUNT(cnt) (cnt)++
155 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
156 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
158 #define REPLACE_COUNT_DIST(array, val) \
160 int limit = (sizeof(array) / sizeof(int)) - 1; \
161 if ((val) < (limit)) (array)[val]++; \
162 else (array)[limit]++; \
165 static void replace_statistics_source_frame(sourceframe_t *frame);
169 #define REPLACE_COUNT(cnt)
170 #define REPLACE_COUNT_IF(cnt, cond)
171 #define REPLACE_COUNT_INC(cnt, inc)
172 #define REPLACE_COUNT_DIST(array, val)
174 #endif /* defined(REPLACE_STATISTICS) */
177 /*** constants used internally ************************************************/
179 #define TOP_IS_NORMAL 0
180 #define TOP_IS_ON_STACK 1
181 #define TOP_IS_IN_ITMP1 2
182 #define TOP_IS_VOID 3
185 /******************************************************************************/
186 /* PART I: Creating / freeing replacement points */
187 /******************************************************************************/
190 /* replace_create_replacement_point ********************************************
192 Create a replacement point.
195 jd...............current jitdata
196 iinfo............inlining info for the current position
197 rp...............pre-allocated (uninitialized) rplpoint
198 type.............RPLPOINT_TYPE constant
199 iptr.............current instruction
200 *pra.............current rplalloc pointer
201 javalocals.......the javalocals at the current point
202 stackvars........the stack variables at the current point
203 stackdepth.......the stack depth at the current point
204 paramcount.......number of parameters at the start of stackvars
207 *rpa.............points to the next free rplalloc
209 *******************************************************************************/
211 static void replace_create_replacement_point(jitdata *jd,
212 insinfo_inline *iinfo,
229 REPLACE_COUNT(stat_rploints);
231 rp->method = (iinfo) ? iinfo->method : jd->m;
232 rp->pc = NULL; /* set by codegen */
233 rp->callsize = 0; /* set by codegen */
237 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
239 /* XXX unify these two fields */
240 rp->parent = (iinfo) ? iinfo->rp : NULL;
242 /* store local allocation info of javalocals */
245 for (i = 0; i < rp->method->maxlocals; ++i) {
246 index = javalocals[i];
253 ra->flags = v->flags & (INMEMORY);
254 ra->regoff = v->vv.regoff;
258 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
266 /* store allocation info of java stack vars */
268 for (i = 0; i < stackdepth; ++i) {
269 v = VAR(stackvars[i]);
270 ra->flags = v->flags & (INMEMORY);
271 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
273 /* XXX how to handle locals on the stack containing returnAddresses? */
274 if (v->type == TYPE_RET) {
275 assert(stackvars[i] >= jd->localcount);
276 ra->regoff = v->vv.retaddr->nr;
279 ra->regoff = v->vv.regoff;
283 /* total number of allocations */
285 rp->regalloccount = ra - rp->regalloc;
291 /* replace_create_inline_start_replacement_point *******************************
293 Create an INLINE_START replacement point.
296 jd...............current jitdata
297 rp...............pre-allocated (uninitialized) rplpoint
298 iptr.............current instruction
299 *pra.............current rplalloc pointer
300 javalocals.......the javalocals at the current point
303 *rpa.............points to the next free rplalloc
306 the insinfo_inline * for the following inlined body
308 *******************************************************************************/
310 static insinfo_inline * replace_create_inline_start_replacement_point(
317 insinfo_inline *calleeinfo;
320 calleeinfo = iptr->sx.s23.s3.inlineinfo;
324 replace_create_replacement_point(jd, calleeinfo->parent, rp,
325 RPLPOINT_TYPE_INLINE, iptr, pra,
327 calleeinfo->stackvars, calleeinfo->stackvarscount,
328 calleeinfo->paramcount);
330 if (calleeinfo->synclocal != UNUSED) {
332 ra->index = RPLALLOC_SYNC;
333 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
334 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
344 /* replace_create_replacement_points *******************************************
346 Create the replacement points for the given code.
349 jd...............current jitdata, must not have any replacement points
352 code->rplpoints.......set to the list of replacement points
353 code->rplpointcount...number of replacement points
354 code->regalloc........list of allocation info
355 code->regalloccount...total length of allocation info list
356 code->globalcount.....number of global allocations at the
357 start of code->regalloc
360 true.............everything ok
361 false............an exception has been thrown
363 *******************************************************************************/
365 #define CLEAR_javalocals(array, method) \
367 for (i=0; i<(method)->maxlocals; ++i) \
368 (array)[i] = UNUSED; \
371 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
373 if ((array) != NULL) \
374 MCOPY((dest), (array), s4, (method)->maxlocals); \
376 CLEAR_javalocals((dest), (method)); \
379 #define COUNT_javalocals(array, method, counter) \
381 for (i=0; i<(method)->maxlocals; ++i) \
382 if ((array)[i] != UNUSED) \
386 bool replace_create_replacement_points(jitdata *jd)
404 insinfo_inline *iinfo;
407 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
411 REPLACE_COUNT(stat_methods);
413 /* get required compiler data */
418 /* assert that we wont overwrite already allocated data */
422 assert(code->rplpoints == NULL);
423 assert(code->rplpointcount == 0);
424 assert(code->regalloc == NULL);
425 assert(code->regalloccount == 0);
426 assert(code->globalcount == 0);
430 /* in instance methods, we may need a rplpoint at the method entry */
432 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
433 if (!(m->flags & ACC_STATIC)) {
434 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
440 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
442 /* iterate over the basic block list to find replacement points */
447 javalocals = DMNEW(s4, jd->maxlocals);
449 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
453 if (bptr->flags < BBFINISHED)
456 /* get info about this block */
459 iinfo = bptr->inlineinfo;
461 /* initialize javalocals at the start of this block */
463 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
465 /* iterate over the instructions */
468 iend = iptr + bptr->icount;
472 for (; iptr != iend; ++iptr) {
474 #if defined(ENABLE_GC_CACAO)
476 md = iptr->sx.s23.s3.bte->md;
478 COUNT_javalocals(javalocals, m, alloccount);
479 alloccount += iptr->s1.argcount;
481 alloccount -= iinfo->throughcount;
485 case ICMD_INVOKESTATIC:
486 case ICMD_INVOKESPECIAL:
487 case ICMD_INVOKEVIRTUAL:
488 case ICMD_INVOKEINTERFACE:
489 INSTRUCTION_GET_METHODDESC(iptr, md);
491 COUNT_javalocals(javalocals, m, alloccount);
492 alloccount += iptr->s1.argcount;
494 alloccount -= iinfo->throughcount;
502 stack_javalocals_store(iptr, javalocals);
516 case ICMD_INLINE_START:
517 iinfo = iptr->sx.s23.s3.inlineinfo;
520 COUNT_javalocals(javalocals, m, alloccount);
521 alloccount += iinfo->stackvarscount;
522 if (iinfo->synclocal != UNUSED)
526 /* javalocals may be set at next block start, or now */
527 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
530 case ICMD_INLINE_BODY:
531 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
533 jl = iinfo->javalocals_start;
535 /* get the javalocals from the following block start */
537 jl = bptr->next->javalocals;
540 COUNT_javalocals(jl, m, alloccount);
543 case ICMD_INLINE_END:
544 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
545 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
546 iinfo = iptr->sx.s23.s3.inlineinfo;
548 if (iinfo->javalocals_end)
549 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
550 iinfo = iinfo->parent;
554 if (iptr == bptr->iinstr)
556 } /* end instruction loop */
558 /* create replacement points at targets of backward branches */
559 /* We only need the replacement point there, if there is no */
560 /* replacement point inside the block. */
562 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
563 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
564 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
568 if (test > startcount) {
569 /* we don't need an extra rplpoint */
570 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
574 alloccount += bptr->indepth;
575 if (bptr->inlineinfo)
576 alloccount -= bptr->inlineinfo->throughcount;
578 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
582 } /* end basicblock loop */
584 /* if no points were found, there's nothing to do */
589 /* allocate replacement point array and allocation array */
591 rplpoints = MNEW(rplpoint, count);
592 regalloc = MNEW(rplalloc, alloccount);
595 /* initialize replacement point structs */
599 /* XXX try to share code with the counting loop! */
601 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
604 if (bptr->flags < BBFINISHED)
607 /* get info about this block */
610 iinfo = bptr->inlineinfo;
612 /* initialize javalocals at the start of this block */
614 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
616 /* create replacement points at targets of backward branches */
618 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
620 i = (iinfo) ? iinfo->throughcount : 0;
621 replace_create_replacement_point(jd, iinfo, rp++,
622 bptr->type, bptr->iinstr, &ra,
623 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
625 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
626 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
629 /* iterate over the instructions */
632 iend = iptr + bptr->icount;
634 for (; iptr != iend; ++iptr) {
636 #if defined(ENABLE_GC_CACAO)
638 md = iptr->sx.s23.s3.bte->md;
640 i = (iinfo) ? iinfo->throughcount : 0;
641 replace_create_replacement_point(jd, iinfo, rp++,
642 RPLPOINT_TYPE_CALL, iptr, &ra,
643 javalocals, iptr->sx.s23.s2.args,
644 iptr->s1.argcount - i,
649 case ICMD_INVOKESTATIC:
650 case ICMD_INVOKESPECIAL:
651 case ICMD_INVOKEVIRTUAL:
652 case ICMD_INVOKEINTERFACE:
653 INSTRUCTION_GET_METHODDESC(iptr, md);
655 i = (iinfo) ? iinfo->throughcount : 0;
656 replace_create_replacement_point(jd, iinfo, rp++,
657 RPLPOINT_TYPE_CALL, iptr, &ra,
658 javalocals, iptr->sx.s23.s2.args,
659 iptr->s1.argcount - i,
668 stack_javalocals_store(iptr, javalocals);
676 replace_create_replacement_point(jd, iinfo, rp++,
677 RPLPOINT_TYPE_RETURN, iptr, &ra,
678 NULL, &(iptr->s1.varindex), 1, 0);
682 replace_create_replacement_point(jd, iinfo, rp++,
683 RPLPOINT_TYPE_RETURN, iptr, &ra,
687 case ICMD_INLINE_START:
688 iinfo = replace_create_inline_start_replacement_point(
689 jd, rp++, iptr, &ra, javalocals);
691 /* javalocals may be set at next block start, or now */
692 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
695 case ICMD_INLINE_BODY:
696 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
698 jl = iinfo->javalocals_start;
700 /* get the javalocals from the following block start */
702 jl = bptr->next->javalocals;
704 /* create a non-trappable rplpoint */
705 replace_create_replacement_point(jd, iinfo, rp++,
706 RPLPOINT_TYPE_BODY, iptr, &ra,
708 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
711 case ICMD_INLINE_END:
712 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
713 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
714 iinfo = iptr->sx.s23.s3.inlineinfo;
716 if (iinfo->javalocals_end)
717 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
718 iinfo = iinfo->parent;
721 } /* end instruction loop */
722 } /* end basicblock loop */
724 assert((rp - rplpoints) == count);
725 assert((ra - regalloc) == alloccount);
727 /* store the data in the codeinfo */
729 code->rplpoints = rplpoints;
730 code->rplpointcount = count;
731 code->regalloc = regalloc;
732 code->regalloccount = alloccount;
733 code->globalcount = 0;
734 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
735 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
736 #if defined(HAS_ADDRESS_REGISTER_FILE)
737 code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
739 code->memuse = rd->memuse;
740 code->stackframesize = jd->cd->stackframesize;
742 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
743 REPLACE_COUNT_INC(stat_regallocs, alloccount);
745 /* everything alright */
751 /* replace_free_replacement_points *********************************************
753 Free memory used by replacement points.
756 code.............codeinfo whose replacement points should be freed.
758 *******************************************************************************/
760 void replace_free_replacement_points(codeinfo *code)
765 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
768 MFREE(code->regalloc,rplalloc,code->regalloccount);
770 code->rplpoints = NULL;
771 code->rplpointcount = 0;
772 code->regalloc = NULL;
773 code->regalloccount = 0;
774 code->globalcount = 0;
778 /******************************************************************************/
779 /* PART II: Activating / deactivating replacement points */
780 /******************************************************************************/
783 /* replace_activate_replacement_points *****************************************
785 Activate the replacement points of the given compilation unit. When this
786 function returns, the replacement points are "armed", so each thread
787 reaching one of the points will enter the replacement mechanism.
790 code.............codeinfo of which replacement points should be
792 mappable.........if true, only mappable replacement points are
795 *******************************************************************************/
797 void replace_activate_replacement_points(codeinfo *code, bool mappable)
804 assert(code->savedmcode == NULL);
806 /* count trappable replacement points */
809 i = code->rplpointcount;
810 rp = code->rplpoints;
812 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
815 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
821 /* allocate buffer for saved machine code */
823 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
824 code->savedmcode = savedmcode;
825 savedmcode += count * REPLACEMENT_PATCH_SIZE;
827 /* activate trappable replacement points */
828 /* (in reverse order to handle overlapping points within basic blocks) */
830 i = code->rplpointcount;
831 rp = code->rplpoints + i;
833 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
835 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
838 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
841 DOLOG( printf("activate replacement point:\n");
842 replace_replacement_point_println(rp, 1); fflush(stdout); );
844 savedmcode -= REPLACEMENT_PATCH_SIZE;
846 #if defined(ENABLE_JIT)
847 # if defined(ENABLE_DISASSEMBLER)
848 DOLOG( printf("\tinstruction before: ");
849 disassinstr(rp->pc); fflush(stdout); );
852 md_patch_replacement_point(rp->pc, savedmcode, false);
854 # if defined(ENABLE_DISASSEMBLER)
855 DOLOG( printf("\tinstruction after : ");
856 disassinstr(rp->pc); fflush(stdout); );
860 rp->flags |= RPLPOINT_FLAG_ACTIVE;
863 assert(savedmcode == code->savedmcode);
867 /* replace_deactivate_replacement_points ***************************************
869 Deactivate a replacement points in the given compilation unit.
870 When this function returns, the replacement points will be "un-armed",
871 that is a each thread reaching a point will just continue normally.
874 code.............the compilation unit
876 *******************************************************************************/
878 void replace_deactivate_replacement_points(codeinfo *code)
885 if (code->savedmcode == NULL) {
886 /* disarm countdown points by patching the branches */
888 i = code->rplpointcount;
889 rp = code->rplpoints;
891 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
892 == RPLPOINT_FLAG_COUNTDOWN)
895 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
902 assert(code->savedmcode != NULL);
903 savedmcode = code->savedmcode;
905 /* de-activate each trappable replacement point */
907 i = code->rplpointcount;
908 rp = code->rplpoints;
911 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
916 DOLOG( printf("deactivate replacement point:\n");
917 replace_replacement_point_println(rp, 1); fflush(stdout); );
919 #if defined(ENABLE_JIT)
920 # if defined(ENABLE_DISASSEMBLER)
921 DOLOG( printf("\tinstruction before: ");
922 disassinstr(rp->pc); fflush(stdout); );
925 md_patch_replacement_point(rp->pc, savedmcode, true);
927 # if defined(ENABLE_DISASSEMBLER)
928 DOLOG( printf("\tinstruction before: ");
929 disassinstr(rp->pc); fflush(stdout); );
933 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
935 savedmcode += REPLACEMENT_PATCH_SIZE;
938 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
940 /* free saved machine code */
942 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
943 code->savedmcode = NULL;
947 /******************************************************************************/
948 /* PART III: The replacement mechanism */
949 /******************************************************************************/
952 /* replace_read_value **********************************************************
954 Read a value with the given allocation from the execution state.
957 es...............execution state
958 ra...............allocation
959 javaval..........where to put the value
962 *javaval.........the value
964 *******************************************************************************/
966 static void replace_read_value(executionstate_t *es,
968 replace_val_t *javaval)
970 if (ra->flags & INMEMORY) {
971 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
972 #ifdef HAS_4BYTE_STACKSLOT
973 if (IS_2_WORD_TYPE(ra->type)) {
974 javaval->l = *(u8*)(es->sp + ra->regoff);
978 javaval->p = *(ptrint*)(es->sp + ra->regoff);
979 #ifdef HAS_4BYTE_STACKSLOT
984 /* allocated register */
985 if (IS_FLT_DBL_TYPE(ra->type)) {
986 javaval->d = es->fltregs[ra->regoff];
988 if (ra->type == TYPE_FLT)
989 javaval->f = javaval->d;
991 #if defined(HAS_ADDRESS_REGISTER_FILE)
992 else if (IS_ADR_TYPE(ra->type)) {
993 javaval->p = es->adrregs[ra->regoff];
997 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
998 if (ra->type == TYPE_LNG) {
999 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
1000 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
1003 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
1004 javaval->p = es->intregs[ra->regoff];
1010 /* replace_write_value *********************************************************
1012 Write a value to the given allocation in the execution state.
1015 es...............execution state
1016 ra...............allocation
1017 *javaval.........the value
1019 *******************************************************************************/
1021 static void replace_write_value(executionstate_t *es,
1023 replace_val_t *javaval)
1025 if (ra->flags & INMEMORY) {
1026 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1027 #ifdef HAS_4BYTE_STACKSLOT
1028 if (IS_2_WORD_TYPE(ra->type)) {
1029 *(u8*)(es->sp + ra->regoff) = javaval->l;
1033 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1034 #ifdef HAS_4BYTE_STACKSLOT
1039 /* allocated register */
1042 es->fltregs[ra->regoff] = (double) javaval->f;
1045 es->fltregs[ra->regoff] = javaval->d;
1047 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1049 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1050 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1053 #if defined(HAS_ADDRESS_REGISTER_FILE)
1055 es->adrregs[ra->regoff] = javaval->p;
1058 es->intregs[ra->regoff] = javaval->p;
1064 /* replace_new_sourceframe *****************************************************
1066 Allocate a new source frame and insert it at the front of the frame list.
1069 ss...............the source state
1072 ss->frames.......set to new frame (the new head of the frame list).
1075 returns the new frame
1077 *******************************************************************************/
1079 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1081 sourceframe_t *frame;
1083 frame = DNEW(sourceframe_t);
1084 MZERO(frame, sourceframe_t, 1);
1086 frame->down = ss->frames;
1093 /* replace_read_executionstate *************************************************
1095 Read a source frame from the given executions state.
1096 The new source frame is pushed to the front of the frame list of the
1100 rp...............replacement point at which `es` was taken
1101 es...............execution state
1102 ss...............the source state to add the source frame to
1103 topframe.........true, if the first (top-most) source frame on the
1107 *ss..............the source state with the newly created source frame
1110 *******************************************************************************/
1112 static s4 replace_normalize_type_map[] = {
1113 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1114 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1115 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1116 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1117 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1118 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1119 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1123 static void replace_read_executionstate(rplpoint *rp,
1124 executionstate_t *es,
1133 sourceframe_t *frame;
1136 stackslot_t *basesp;
1138 code = code_find_codeinfo_for_pc(rp->pc);
1140 topslot = TOP_IS_NORMAL;
1144 sp = (stackslot_t *) es->sp;
1146 /* in some cases the top stack slot is passed in REG_ITMP1 */
1148 if (rp->type == BBTYPE_EXH) {
1149 topslot = TOP_IS_IN_ITMP1;
1152 /* calculate base stack pointer */
1154 basesp = sp + code->stackframesize;
1156 /* create the source frame */
1158 frame = replace_new_sourceframe(ss);
1159 frame->method = rp->method;
1161 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1162 frame->type = replace_normalize_type_map[rp->type];
1164 frame->fromcode = code;
1166 /* read local variables */
1168 count = m->maxlocals;
1169 frame->javalocalcount = count;
1170 frame->javalocals = DMNEW(replace_val_t, count);
1171 frame->javalocaltype = DMNEW(u1, count);
1173 /* mark values as undefined */
1174 for (i=0; i<count; ++i) {
1175 #if !defined(NDEBUG)
1176 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1178 frame->javalocaltype[i] = TYPE_VOID;
1181 /* some entries in the intregs array are not meaningful */
1182 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1183 #if !defined(NDEBUG)
1184 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1186 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1188 #endif /* !defined(NDEBUG) */
1190 /* read javalocals */
1192 count = rp->regalloccount;
1195 while (count && (i = ra->index) >= 0) {
1196 assert(i < m->maxlocals);
1197 frame->javalocaltype[i] = ra->type;
1198 if (ra->type == TYPE_RET)
1199 frame->javalocals[i].i = ra->regoff;
1201 replace_read_value(es, ra, frame->javalocals + i);
1206 /* read instance, if this is the first rplpoint */
1208 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1209 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1211 /* we are at the start of the method body, so if local 0 is set, */
1212 /* it is the instance. */
1213 if (frame->javalocaltype[0] == TYPE_ADR)
1214 frame->instance = frame->javalocals[0];
1219 md = rp->method->parseddesc;
1221 assert(md->paramcount >= 1);
1222 instra.type = TYPE_ADR;
1223 instra.regoff = md->params[0].regoff;
1224 if (md->params[0].inmemory) {
1225 instra.flags = INMEMORY;
1226 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1231 replace_read_value(es, &instra, &(frame->instance));
1234 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1236 /* read stack slots */
1238 frame->javastackdepth = count;
1239 frame->javastack = DMNEW(replace_val_t, count);
1240 frame->javastacktype = DMNEW(u1, count);
1242 #if !defined(NDEBUG)
1243 /* mark values as undefined */
1244 for (i=0; i<count; ++i) {
1245 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1246 frame->javastacktype[i] = TYPE_VOID;
1248 #endif /* !defined(NDEBUG) */
1252 /* the first stack slot is special in SBR and EXH blocks */
1254 if (topslot == TOP_IS_ON_STACK) {
1257 assert(ra->index == RPLALLOC_STACK);
1258 assert(ra->type == TYPE_ADR);
1259 frame->javastack[i].p = sp[-1];
1260 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1265 else if (topslot == TOP_IS_IN_ITMP1) {
1268 assert(ra->index == RPLALLOC_STACK);
1269 assert(ra->type == TYPE_ADR);
1270 frame->javastack[i].p = es->intregs[REG_ITMP1];
1271 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1276 else if (topslot == TOP_IS_VOID) {
1279 assert(ra->index == RPLALLOC_STACK);
1280 frame->javastack[i].l = 0;
1281 frame->javastacktype[i] = TYPE_VOID;
1287 /* read remaining stack slots */
1289 for (; count--; ra++) {
1290 if (ra->index == RPLALLOC_SYNC) {
1291 assert(rp->type == RPLPOINT_TYPE_INLINE);
1293 /* only read synchronization slots when traversing an inline point */
1296 sourceframe_t *calleeframe = frame->down;
1297 assert(calleeframe);
1298 assert(calleeframe->syncslotcount == 0);
1299 assert(calleeframe->syncslots == NULL);
1301 calleeframe->syncslotcount = 1;
1302 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1303 replace_read_value(es,ra,calleeframe->syncslots);
1306 frame->javastackdepth--;
1310 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1312 /* do not read parameters of calls down the call chain */
1314 if (!topframe && ra->index == RPLALLOC_PARAM) {
1315 frame->javastackdepth--;
1318 if (ra->type == TYPE_RET)
1319 frame->javastack[i].i = ra->regoff;
1321 replace_read_value(es,ra,frame->javastack + i);
1322 frame->javastacktype[i] = ra->type;
1329 /* replace_write_executionstate ************************************************
1331 Pop a source frame from the front of the frame list of the given source state
1332 and write its values into the execution state.
1335 rp...............replacement point for which execution state should be
1337 es...............the execution state to modify
1338 ss...............the given source state
1339 topframe.........true, if this is the last (top-most) source frame to be
1343 *es..............the execution state derived from the source state
1345 *******************************************************************************/
1347 static void replace_write_executionstate(rplpoint *rp,
1348 executionstate_t *es,
1357 sourceframe_t *frame;
1360 stackslot_t *basesp;
1362 code = code_find_codeinfo_for_pc(rp->pc);
1364 topslot = TOP_IS_NORMAL;
1366 /* pop a source frame */
1370 ss->frames = frame->down;
1372 /* calculate stack pointer */
1374 sp = (stackslot_t *) es->sp;
1376 basesp = sp + code->stackframesize;
1378 /* in some cases the top stack slot is passed in REG_ITMP1 */
1380 if (rp->type == BBTYPE_EXH) {
1381 topslot = TOP_IS_IN_ITMP1;
1384 /* write javalocals */
1387 count = rp->regalloccount;
1389 while (count && (i = ra->index) >= 0) {
1390 assert(i < m->maxlocals);
1391 assert(i < frame->javalocalcount);
1392 assert(ra->type == frame->javalocaltype[i]);
1393 if (ra->type == TYPE_RET) {
1394 /* XXX assert that it matches this rplpoint */
1397 replace_write_value(es, ra, frame->javalocals + i);
1402 /* write stack slots */
1406 /* the first stack slot is special in SBR and EXH blocks */
1408 if (topslot == TOP_IS_ON_STACK) {
1411 assert(ra->index == RPLALLOC_STACK);
1412 assert(i < frame->javastackdepth);
1413 assert(frame->javastacktype[i] == TYPE_ADR);
1414 sp[-1] = frame->javastack[i].p;
1419 else if (topslot == TOP_IS_IN_ITMP1) {
1422 assert(ra->index == RPLALLOC_STACK);
1423 assert(i < frame->javastackdepth);
1424 assert(frame->javastacktype[i] == TYPE_ADR);
1425 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1430 else if (topslot == TOP_IS_VOID) {
1433 assert(ra->index == RPLALLOC_STACK);
1434 assert(i < frame->javastackdepth);
1435 assert(frame->javastacktype[i] == TYPE_VOID);
1441 /* write remaining stack slots */
1443 for (; count--; ra++) {
1444 if (ra->index == RPLALLOC_SYNC) {
1445 assert(rp->type == RPLPOINT_TYPE_INLINE);
1447 /* only write synchronization slots when traversing an inline point */
1450 assert(frame->down);
1451 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1452 assert(frame->down->syncslots != NULL);
1454 replace_write_value(es,ra,frame->down->syncslots);
1459 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1461 /* do not write parameters of calls down the call chain */
1463 if (!topframe && ra->index == RPLALLOC_PARAM) {
1467 assert(i < frame->javastackdepth);
1468 assert(ra->type == frame->javastacktype[i]);
1469 if (ra->type == TYPE_RET) {
1470 /* XXX assert that it matches this rplpoint */
1473 replace_write_value(es,ra,frame->javastack + i);
1485 /* replace_pop_activation_record ***********************************************
1487 Peel a stack frame from the execution state.
1489 *** This function imitates the effects of the method epilog ***
1490 *** and returning from the method call. ***
1493 es...............execution state
1494 frame............source frame, receives synchronization slots
1497 *es..............the execution state after popping the stack frame
1499 *******************************************************************************/
1501 u1* replace_pop_activation_record(executionstate_t *es,
1502 sourceframe_t *frame)
1510 stackslot_t *basesp;
1516 /* read the return address */
1518 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1519 if (code_is_leafmethod(es->code))
1520 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1523 ra = md_stacktrace_get_returnaddress(es->sp,
1524 SIZE_OF_STACKSLOT * es->code->stackframesize);
1526 DOLOG( printf("RA = %p\n", (void*)ra); );
1530 /* calculate the base of the stack frame */
1532 sp = (stackslot_t *) es->sp;
1533 basesp = sp + es->code->stackframesize;
1535 /* read slots used for synchronization */
1537 assert(frame->syncslotcount == 0);
1538 assert(frame->syncslots == NULL);
1539 count = code_get_sync_slot_count(es->code);
1540 frame->syncslotcount = count;
1541 frame->syncslots = DMNEW(replace_val_t, count);
1542 for (i=0; i<count; ++i) {
1543 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1546 /* restore return address, if part of frame */
1548 #if defined(REPLACE_RA_TOP_OF_FRAME)
1549 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1550 if (!code_is_leafmethod(es->code))
1552 es->intregs[REPLACE_REG_RA] = *--basesp;
1553 #endif /* REPLACE_RA_TOP_OF_FRAME */
1555 #if defined(REPLACE_RA_LINKAGE_AREA)
1556 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1557 if (!code_is_leafmethod(es->code))
1559 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1560 #endif /* REPLACE_RA_LINKAGE_AREA */
1562 /* restore saved int registers */
1565 for (i=0; i<es->code->savedintcount; ++i) {
1566 while (nregdescint[--reg] != REG_SAV)
1568 es->intregs[reg] = *--basesp;
1571 /* restore saved flt registers */
1575 for (i=0; i<es->code->savedfltcount; ++i) {
1576 while (nregdescfloat[--reg] != REG_SAV)
1578 basesp -= STACK_SLOTS_PER_FLOAT;
1579 es->fltregs[reg] = *(double*)basesp;
1582 #if defined(HAS_ADDRESS_REGISTER_FILE)
1583 /* restore saved adr registers */
1586 for (i=0; i<es->code->savedadrcount; ++i) {
1587 while (nregdescadr[--reg] != REG_SAV)
1589 es->adrregs[reg] = *--basesp;
1593 /* adjust the stackpointer */
1595 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1597 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1598 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1601 /* Set the new pc. Subtract one so we do not hit the replacement point */
1602 /* of the instruction following the call, if there is one. */
1606 /* find the new codeinfo */
1608 pv = md_codegen_get_pv_from_pc(ra);
1609 DOLOG( printf("PV = %p\n", (void*) pv); );
1611 code = code_get_codeinfo_for_pv(pv);
1612 DOLOG( printf("CODE = %p\n", (void*) code); );
1614 /* return NULL if we reached native code */
1619 /* in debugging mode clobber non-saved registers */
1621 #if !defined(NDEBUG)
1623 for (i=0; i<INT_REG_CNT; ++i)
1624 if ((nregdescint[i] != REG_SAV)
1626 && (i != REPLACE_REG_RA)
1629 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1630 for (i=0; i<FLT_REG_CNT; ++i)
1631 if (nregdescfloat[i] != REG_SAV)
1632 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1633 # if defined(HAS_ADDRESS_REGISTER_FILE)
1634 for (i=0; i<ADR_REG_CNT; ++i)
1635 if (nregdescadr[i] != REG_SAV)
1636 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1638 #endif /* !defined(NDEBUG) */
1640 return (code) ? ra : NULL;
1644 /* replace_patch_method_pointer ************************************************
1646 Patch a method pointer (may be in code, data segment, vftbl, or interface
1650 mpp..............address of the method pointer to patch
1651 entrypoint.......the new entrypoint of the method
1652 kind.............kind of call to patch, used only for debugging
1654 *******************************************************************************/
1656 static void replace_patch_method_pointer(methodptr *mpp,
1657 methodptr entrypoint,
1660 #if !defined(NDEBUG)
1665 DOLOG( printf("patch method pointer from: %p to %p\n",
1666 (void*) *mpp, (void*)entrypoint); );
1668 #if !defined(NDEBUG)
1669 oldcode = code_get_codeinfo_for_pv(*mpp);
1670 newcode = code_get_codeinfo_for_pv(entrypoint);
1672 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1673 method_println(oldcode->m);
1674 printf("\t with %p ", (void*) newcode);
1675 method_println(newcode->m); );
1677 assert(oldcode->m == newcode->m);
1680 /* write the new entrypoint */
1682 *mpp = (methodptr) entrypoint;
1686 /* replace_patch_class *********************************************************
1688 Patch a method in the given class.
1691 vftbl............vftbl of the class
1692 m................the method to patch
1693 oldentrypoint....the old entrypoint to replace
1694 entrypoint.......the new entrypoint
1696 *******************************************************************************/
1698 void replace_patch_class(vftbl_t *vftbl,
1707 /* patch the vftbl of the class */
1709 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1713 /* patch the interface tables */
1715 assert(oldentrypoint);
1717 for (i=0; i < vftbl->interfacetablelength; ++i) {
1718 mpp = vftbl->interfacetable[-i];
1719 mppend = mpp + vftbl->interfacevftbllength[i];
1720 for (; mpp != mppend; ++mpp)
1721 if (*mpp == oldentrypoint) {
1722 replace_patch_method_pointer(mpp, entrypoint, "interface");
1728 /* replace_patch_class_hierarchy ***********************************************
1730 Patch a method in all loaded classes.
1733 m................the method to patch
1734 oldentrypoint....the old entrypoint to replace
1735 entrypoint.......the new entrypoint
1737 *******************************************************************************/
1739 struct replace_patch_data_t {
1745 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1747 vftbl_t *vftbl = c->vftbl;
1750 && vftbl->vftbllength > pd->m->vftblindex
1751 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1752 && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
1754 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1758 void replace_patch_class_hierarchy(methodinfo *m,
1762 struct replace_patch_data_t pd;
1765 pd.oldentrypoint = oldentrypoint;
1766 pd.entrypoint = entrypoint;
1768 DOLOG_SHORT( printf("patching class hierarchy: ");
1769 method_println(m); );
1771 classcache_foreach_loaded_class(
1772 (classcache_foreach_functionptr_t) &replace_patch_callback,
1777 /* replace_patch_future_calls **************************************************
1779 Analyse a call site and depending on the kind of call patch the call, the
1780 virtual function table, or the interface table.
1783 ra...............return address pointing after the call site
1784 callerframe......source frame of the caller
1785 calleeframe......source frame of the callee, must have been mapped
1787 *******************************************************************************/
1789 void replace_patch_future_calls(u1 *ra,
1790 sourceframe_t *callerframe,
1791 sourceframe_t *calleeframe)
1794 methodptr entrypoint;
1795 methodptr oldentrypoint;
1798 codeinfo *calleecode;
1799 methodinfo *calleem;
1804 assert(callerframe->down == calleeframe);
1806 /* get the new codeinfo and the method that shall be entered */
1808 calleecode = calleeframe->tocode;
1811 calleem = calleeframe->method;
1812 assert(calleem == calleecode->m);
1814 entrypoint = (methodptr) calleecode->entrypoint;
1816 /* check if we are at an method entry rplpoint at the innermost frame */
1818 atentry = (calleeframe->down == NULL)
1819 && !(calleem->flags & ACC_STATIC)
1820 && (calleeframe->fromrp->id == 0); /* XXX */
1822 /* get the position to patch, in case it was a statically bound call */
1824 pv = callerframe->fromcode->entrypoint;
1825 patchpos = md_jit_method_patch_address(pv, ra, NULL);
1827 if (patchpos == NULL) {
1828 /* the call was dispatched dynamically */
1830 /* we can only patch such calls if we are at the entry point */
1835 assert((calleem->flags & ACC_STATIC) == 0);
1837 oldentrypoint = calleeframe->fromcode->entrypoint;
1839 /* we need to know the instance */
1841 if (!calleeframe->instance.a) {
1842 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1843 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1849 obj = calleeframe->instance.a;
1852 assert(vftbl->class->vftbl == vftbl);
1854 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1856 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1859 /* the call was statically bound */
1861 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1866 /* replace_push_activation_record **********************************************
1868 Push a stack frame onto the execution state.
1870 *** This function imitates the effects of a call and the ***
1871 *** method prolog of the callee. ***
1874 es...............execution state
1875 rpcall...........the replacement point at the call site
1876 callerframe......source frame of the caller, or NULL for creating the
1878 calleeframe......source frame of the callee, must have been mapped
1881 *es..............the execution state after pushing the stack frame
1883 *******************************************************************************/
1885 void replace_push_activation_record(executionstate_t *es,
1887 sourceframe_t *callerframe,
1888 sourceframe_t *calleeframe)
1893 stackslot_t *basesp;
1896 codeinfo *calleecode;
1899 assert(!rpcall || callerframe);
1900 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1901 assert(!rpcall || rpcall == callerframe->torp);
1902 assert(calleeframe);
1903 assert(!callerframe || calleeframe == callerframe->down);
1905 /* the compilation unit we are entering */
1907 calleecode = calleeframe->tocode;
1910 /* calculate the return address */
1913 ra = rpcall->pc + rpcall->callsize;
1915 ra = es->pc + 1 /* XXX this is ugly */;
1917 /* write the return address */
1919 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1920 es->sp -= SIZE_OF_STACKSLOT;
1922 *((stackslot_t *)es->sp) = (stackslot_t) ra;
1923 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1925 #if defined(REPLACE_REG_RA)
1926 es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1929 /* we move into a new code unit */
1931 es->code = calleecode;
1933 /* set the new pc XXX not needed? */
1935 es->pc = calleecode->entrypoint;
1937 /* build the stackframe */
1939 DOLOG( printf("building stackframe of %d words at %p\n",
1940 calleecode->stackframesize, (void*)es->sp); );
1942 sp = (stackslot_t *) es->sp;
1945 sp -= calleecode->stackframesize;
1948 /* in debug mode, invalidate stack frame first */
1950 /* XXX may not invalidate linkage area used by native code! */
1951 #if !defined(NDEBUG) && 0
1952 for (i=0; i<(basesp - sp); ++i) {
1953 sp[i] = 0xdeaddeadU;
1957 /* save the return address register */
1959 #if defined(REPLACE_RA_TOP_OF_FRAME)
1960 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1961 if (!code_is_leafmethod(calleecode))
1963 *--basesp = (ptrint) ra;
1964 #endif /* REPLACE_RA_TOP_OF_FRAME */
1966 #if defined(REPLACE_RA_LINKAGE_AREA)
1967 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1968 if (!code_is_leafmethod(calleecode))
1970 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1971 #endif /* REPLACE_RA_LINKAGE_AREA */
1973 /* save int registers */
1976 for (i=0; i<calleecode->savedintcount; ++i) {
1977 while (nregdescint[--reg] != REG_SAV)
1979 *--basesp = es->intregs[reg];
1981 /* XXX may not clobber saved regs used by native code! */
1982 #if !defined(NDEBUG) && 0
1983 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1987 /* save flt registers */
1991 for (i=0; i<calleecode->savedfltcount; ++i) {
1992 while (nregdescfloat[--reg] != REG_SAV)
1994 basesp -= STACK_SLOTS_PER_FLOAT;
1995 *(double*)basesp = es->fltregs[reg];
1997 /* XXX may not clobber saved regs used by native code! */
1998 #if !defined(NDEBUG) && 0
1999 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
2003 #if defined(HAS_ADDRESS_REGISTER_FILE)
2004 /* save adr registers */
2007 for (i=0; i<calleecode->savedadrcount; ++i) {
2008 while (nregdescadr[--reg] != REG_SAV)
2010 *--basesp = es->adrregs[reg];
2012 /* XXX may not clobber saved regs used by native code! */
2013 #if !defined(NDEBUG) && 0
2014 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
2019 /* write slots used for synchronization */
2021 count = code_get_sync_slot_count(calleecode);
2022 assert(count == calleeframe->syncslotcount);
2023 for (i=0; i<count; ++i) {
2024 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2029 es->pv = calleecode->entrypoint;
2031 /* redirect future invocations */
2033 if (callerframe && rpcall) {
2034 #if defined(REPLACE_PATCH_ALL)
2035 if (rpcall->type == callerframe->fromrp->type)
2037 if (rpcall == callerframe->fromrp)
2039 replace_patch_future_calls(ra, callerframe, calleeframe);
2044 /* replace_find_replacement_point **********************************************
2046 Find the replacement point in the given code corresponding to the
2047 position given in the source frame.
2050 code.............the codeinfo in which to search the rplpoint
2051 frame............the source frame defining the position to look for
2052 parent...........parent replacement point to match
2055 the replacement point
2057 *******************************************************************************/
2059 rplpoint * replace_find_replacement_point(codeinfo *code,
2060 sourceframe_t *frame,
2073 DOLOG( printf("searching replacement point for:\n");
2074 replace_source_frame_println(frame); );
2078 DOLOG( printf("code = %p\n", (void*)code); );
2080 rp = code->rplpoints;
2081 i = code->rplpointcount;
2083 if (rp->id == frame->id && rp->method == frame->method
2084 && rp->parent == parent
2085 && replace_normalize_type_map[rp->type] == frame->type)
2087 /* check if returnAddresses match */
2088 /* XXX optimize: only do this if JSRs in method */
2089 DOLOG( printf("checking match for:");
2090 replace_replacement_point_println(rp, 1); fflush(stdout); );
2093 for (j = rp->regalloccount; j--; ++ra) {
2094 if (ra->type == TYPE_RET) {
2095 if (ra->index == RPLALLOC_STACK) {
2096 assert(stacki < frame->javastackdepth);
2097 if (frame->javastack[stacki].i != ra->regoff)
2102 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2103 if (frame->javalocals[ra->index].i != ra->regoff)
2116 #if !defined(NDEBUG)
2117 printf("candidate replacement points were:\n");
2118 rp = code->rplpoints;
2119 i = code->rplpointcount;
2121 replace_replacement_point_println(rp, 1);
2125 vm_abort("no matching replacement point found");
2126 return NULL; /* NOT REACHED */
2130 /* replace_find_replacement_point_for_pc ***************************************
2132 Find the nearest replacement point at or before the given PC. The
2133 given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
2134 the replacement point to be found.
2137 code.............compilation unit the PC is in
2138 pc...............the machine code PC
2141 the replacement point found, or
2142 NULL if no replacement point was found
2144 *******************************************************************************/
2146 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2152 DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
2153 method_println(code->m); );
2157 rp = code->rplpoints;
2158 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2159 DOLOG( replace_replacement_point_println(rp, 2); );
2160 if (rp->pc <= pc && rp->pc + rp->callsize >= pc)
2168 /* replace_pop_native_frame ****************************************************
2170 Unroll a native frame in the execution state and create a source frame
2174 es...............current execution state
2175 ss...............the current source state
2176 sfi..............stackframeinfo for the native frame
2179 es...............execution state after unrolling the native frame
2180 ss...............gets the added native source frame
2182 *******************************************************************************/
2184 static void replace_pop_native_frame(executionstate_t *es,
2186 stackframeinfo_t *sfi)
2188 sourceframe_t *frame;
2194 frame = replace_new_sourceframe(ss);
2198 /* remember pc and size of native frame */
2200 frame->nativepc = es->pc;
2201 frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2202 assert(frame->nativeframesize >= 0);
2204 /* remember values of saved registers */
2207 for (i=0; i<INT_REG_CNT; ++i) {
2208 if (nregdescint[i] == REG_SAV)
2209 frame->nativesavint[j++] = es->intregs[i];
2213 for (i=0; i<FLT_REG_CNT; ++i) {
2214 if (nregdescfloat[i] == REG_SAV)
2215 frame->nativesavflt[j++] = es->fltregs[i];
2218 #if defined(HAS_ADDRESS_REGISTER_FILE)
2220 for (i=0; i<ADR_REG_CNT; ++i) {
2221 if (nregdescadr[i] == REG_SAV)
2222 frame->nativesavadr[j++] = es->adrregs[i];
2226 /* restore saved registers */
2228 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2230 for (i=0; i<INT_REG_CNT; ++i) {
2231 if (nregdescint[i] == REG_SAV)
2232 es->intregs[i] = sfi->intregs[j++];
2235 /* XXX we don't have them, yet, in the sfi, so clear them */
2237 for (i=0; i<INT_REG_CNT; ++i) {
2238 if (nregdescint[i] == REG_SAV)
2243 /* XXX we don't have float registers in the sfi, so clear them */
2245 for (i=0; i<FLT_REG_CNT; ++i) {
2246 if (nregdescfloat[i] == REG_SAV)
2247 es->fltregs[i] = 0.0;
2250 #if defined(HAS_ADDRESS_REGISTER_FILE)
2251 # if defined(ENABLE_GC_CACAO)
2253 for (i=0; i<ADR_REG_CNT; ++i) {
2254 if (nregdescadr[i] == REG_SAV)
2255 es->adrregs[i] = sfi->adrregs[j++];
2258 for (i=0; i<ADR_REG_CNT; ++i) {
2259 if (nregdescadr[i] == REG_SAV)
2265 /* restore codeinfo of the native stub */
2267 code = code_get_codeinfo_for_pv(sfi->pv);
2269 /* restore sp, pv, pc and codeinfo of the parent method */
2271 /* XXX michi: use this instead:
2272 es->sp = sfi->sp + code->stackframesize; */
2273 es->sp = sfi->sp + (*(s4 *) (sfi->pv + FrameSize));
2274 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2275 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
2277 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2278 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2279 es->code = code_get_codeinfo_for_pv(es->pv);
2283 /* replace_push_native_frame ***************************************************
2285 Rebuild a native frame onto the execution state and remove its source frame.
2287 Note: The native frame is "rebuild" by setting fields like PC and stack
2288 pointer in the execution state accordingly. Values in the
2289 stackframeinfo may be modified, but the actual stack frame of the
2290 native code is not touched.
2293 es...............current execution state
2294 ss...............the current source state
2297 es...............execution state after re-rolling the native frame
2298 ss...............the native source frame is removed
2300 *******************************************************************************/
2302 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2304 sourceframe_t *frame;
2310 DOLOG( printf("pushing native frame\n"); );
2312 /* remove the frame from the source state */
2316 assert(REPLACE_IS_NATIVE_FRAME(frame));
2318 ss->frames = frame->down;
2320 /* skip sp for the native stub */
2322 es->sp -= (*(s4 *) (frame->sfi->pv + FrameSize));
2323 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2324 es->sp -= SIZE_OF_STACKSLOT; /* skip return address */
2327 /* assert that the native frame has not moved */
2329 assert(es->sp == frame->sfi->sp);
2331 /* update saved registers in the stackframeinfo */
2333 #if defined(ENABLE_GC_CACAO)
2335 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2336 for (i=0; i<INT_REG_CNT; ++i) {
2337 if (nregdescint[i] == REG_SAV)
2338 frame->sfi->intregs[j++] = es->intregs[i];
2341 for (i=0; i<ADR_REG_CNT; ++i) {
2342 if (nregdescadr[i] == REG_SAV)
2343 frame->sfi->adrregs[j++] = es->adrregs[i];
2347 /* XXX leave float registers untouched here */
2350 /* restore saved registers */
2353 for (i=0; i<INT_REG_CNT; ++i) {
2354 if (nregdescint[i] == REG_SAV)
2355 es->intregs[i] = frame->nativesavint[j++];
2359 for (i=0; i<FLT_REG_CNT; ++i) {
2360 if (nregdescfloat[i] == REG_SAV)
2361 es->fltregs[i] = frame->nativesavflt[j++];
2364 #if defined(HAS_ADDRESS_REGISTER_FILE)
2366 for (i=0; i<ADR_REG_CNT; ++i) {
2367 if (nregdescadr[i] == REG_SAV)
2368 es->adrregs[i] = frame->nativesavadr[j++];
2372 /* skip the native frame on the machine stack */
2374 es->sp -= frame->nativeframesize;
2376 /* set the pc the next frame must return to */
2378 es->pc = frame->nativepc;
2382 /* replace_recover_source_state ************************************************
2384 Recover the source state from the given replacement point and execution
2388 rp...............replacement point that has been reached, if any
2389 sfi..............stackframeinfo, if called from native code
2390 es...............execution state at the replacement point rp
2395 *******************************************************************************/
2397 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2398 stackframeinfo_t *sfi,
2399 executionstate_t *es)
2404 #if defined(REPLACE_STATISTICS)
2408 /* create the source frame structure in dump memory */
2410 ss = DNEW(sourcestate_t);
2413 /* each iteration of the loop recovers one source frame */
2420 DOLOG( replace_executionstate_println(es); );
2422 /* if we are not at a replacement point, it is a native frame */
2425 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2428 replace_pop_native_frame(es, ss, sfi);
2431 if (es->code == NULL)
2434 goto after_machine_frame;
2437 /* read the values for this source frame from the execution state */
2439 DOLOG( printf("recovering source state for%s:\n",
2440 (ss->frames == NULL) ? " TOPFRAME" : "");
2441 replace_replacement_point_println(rp, 1); );
2443 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2445 #if defined(ENABLE_VMLOG)
2446 vmlog_cacao_unrol_method(ss->frames->method);
2449 #if defined(REPLACE_STATISTICS)
2450 REPLACE_COUNT(stat_frames);
2452 replace_statistics_source_frame(ss->frames);
2455 /* in locked areas (below native frames), identity map the frame */
2458 ss->frames->torp = ss->frames->fromrp;
2459 ss->frames->tocode = ss->frames->fromcode;
2462 /* unroll to the next (outer) frame */
2465 /* this frame is in inlined code */
2467 DOLOG( printf("INLINED!\n"); );
2471 assert(rp->type == RPLPOINT_TYPE_INLINE);
2472 REPLACE_COUNT(stat_unroll_inline);
2475 /* this frame had been called at machine-level. pop it. */
2477 DOLOG( printf("UNWIND\n"); );
2479 ra = replace_pop_activation_record(es, ss->frames);
2481 DOLOG( printf("REACHED NATIVE CODE\n"); );
2485 #if !defined(ENABLE_GC_CACAO)
2486 break; /* XXX remove to activate native frames */
2491 /* find the replacement point at the call site */
2493 after_machine_frame:
2494 rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2497 vm_abort("could not find replacement point while unrolling call");
2499 DOLOG( printf("found replacement point.\n");
2500 replace_replacement_point_println(rp, 1); );
2502 assert(rp->type == RPLPOINT_TYPE_CALL);
2503 REPLACE_COUNT(stat_unroll_call);
2505 } /* end loop over source frames */
2507 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2513 /* replace_map_source_state ****************************************************
2515 Map each source frame in the given source state to a target replacement
2516 point and compilation unit. If no valid code is available for a source
2517 frame, it is (re)compiled.
2520 ss...............the source state
2523 ss...............the source state, modified: The `torp` and `tocode`
2524 fields of each source frame are set.
2527 true.............everything went ok
2528 false............an exception has been thrown
2530 *******************************************************************************/
2532 static bool replace_map_source_state(sourcestate_t *ss)
2534 sourceframe_t *frame;
2537 rplpoint *parent; /* parent of inlined rplpoint */
2538 #if defined(REPLACE_STATISTICS)
2545 /* iterate over the source frames from outermost to innermost */
2547 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2549 /* XXX skip native frames */
2551 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2556 /* map frames which are not already mapped */
2558 if (frame->tocode) {
2559 code = frame->tocode;
2564 assert(frame->torp == NULL);
2566 if (parent == NULL) {
2567 /* find code for this frame */
2569 #if defined(REPLACE_STATISTICS)
2570 oldcode = frame->method->code;
2572 /* request optimization of hot methods and their callers */
2574 if (frame->method->hitcountdown < 0
2575 || (frame->down && frame->down->method->hitcountdown < 0))
2576 jit_request_optimization(frame->method);
2578 code = jit_get_current_code(frame->method);
2581 return false; /* exception */
2583 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2588 /* map this frame */
2590 rp = replace_find_replacement_point(code, frame, parent);
2592 frame->tocode = code;
2596 if (rp->type == RPLPOINT_TYPE_CALL) {
2609 /* replace_map_source_state_identity *******************************************
2611 Map each source frame in the given source state to the same replacement
2612 point and compilation unit it was derived from. This is mainly used for
2616 ss...............the source state
2619 ss...............the source state, modified: The `torp` and `tocode`
2620 fields of each source frame are set.
2622 *******************************************************************************/
2624 #if defined(ENABLE_GC_CACAO)
2625 static void replace_map_source_state_identity(sourcestate_t *ss)
2627 sourceframe_t *frame;
2629 /* iterate over the source frames from outermost to innermost */
2631 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2633 /* skip native frames */
2635 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2639 /* map frames using the identity mapping */
2641 if (frame->tocode) {
2642 assert(frame->tocode == frame->fromcode);
2643 assert(frame->torp == frame->fromrp);
2645 assert(frame->tocode == NULL);
2646 assert(frame->torp == NULL);
2647 frame->tocode = frame->fromcode;
2648 frame->torp = frame->fromrp;
2655 /* replace_build_execution_state ***********************************************
2657 Build an execution state for the given (mapped) source state.
2659 !!! CAUTION: This function rewrites the machine stack !!!
2661 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2664 ss...............the source state. Must have been mapped by
2665 replace_map_source_state before.
2666 es...............the base execution state on which to build
2669 *es..............the new execution state
2671 *******************************************************************************/
2673 static void replace_build_execution_state(sourcestate_t *ss,
2674 executionstate_t *es)
2677 sourceframe_t *prevframe;
2684 while (ss->frames) {
2686 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2687 prevframe = ss->frames;
2688 replace_push_native_frame(es, ss);
2694 if (parent == NULL) {
2695 /* create a machine-level stack frame */
2697 DOLOG( printf("pushing activation record for:\n");
2698 if (rp) replace_replacement_point_println(rp, 1);
2699 else printf("\tfirst frame\n"); );
2701 replace_push_activation_record(es, rp, prevframe, ss->frames);
2703 DOLOG( replace_executionstate_println(es); );
2706 rp = ss->frames->torp;
2709 DOLOG( printf("creating execution state for%s:\n",
2710 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2711 replace_replacement_point_println(ss->frames->fromrp, 1);
2712 replace_replacement_point_println(rp, 1); );
2714 es->code = ss->frames->tocode;
2715 prevframe = ss->frames;
2717 #if defined(ENABLE_VMLOG)
2718 vmlog_cacao_rerol_method(ss->frames->method);
2721 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2723 DOLOG( replace_executionstate_println(es); );
2725 if (rp->type == RPLPOINT_TYPE_CALL) {
2736 /* replace_me ******************************************************************
2738 This function is called by the signal handler when a thread reaches
2739 a replacement point. `replace_me` must map the execution state to the
2740 target replacement point and let execution continue there.
2742 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2745 rp...............replacement point that has been reached
2746 es...............execution state read by signal handler
2748 *******************************************************************************/
2750 static void replace_me(rplpoint *rp, executionstate_t *es)
2752 stackframeinfo_t *sfi;
2754 sourceframe_t *frame;
2757 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2758 threadobject *thread;
2762 origcode = es->code;
2765 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2766 stat_replacements, (void*)THREADOBJECT,
2768 method_println(es->code->m); );
2770 DOLOG( replace_replacement_point_println(rp, 1); );
2772 REPLACE_COUNT(stat_replacements);
2774 /* mark start of dump memory area */
2778 /* get the stackframeinfo for the current thread */
2780 sfi = STACKFRAMEINFO;
2782 /* recover source state */
2784 ss = replace_recover_source_state(rp, sfi, es);
2786 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2787 /* if there is a collection pending, we assume the replacement point should
2788 suspend this thread */
2792 thread = THREADOBJECT;
2794 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2796 /* map the sourcestate using the identity mapping */
2797 replace_map_source_state_identity(ss);
2799 /* since we enter the same method again, we turn off rps now */
2800 /* XXX michi: can we really do this? what if the rp was active before
2801 we activated it for the gc? */
2802 replace_deactivate_replacement_points(origcode);
2804 /* remember executionstate and sourcestate for this thread */
2805 GC_EXECUTIONSTATE = es;
2806 GC_SOURCESTATE = ss;
2808 /* really suspend this thread now (PC = 0) */
2809 threads_suspend_ack(NULL, NULL);
2811 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2814 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2816 /* map the source state */
2818 if (!replace_map_source_state(ss))
2819 vm_abort("exception during method replacement");
2821 DOLOG( replace_sourcestate_println(ss); );
2823 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2825 #if !defined(NDEBUG)
2826 /* avoid infinite loops by self-replacement, only if not in testing mode */
2828 if (!opt_TestReplacement) {
2831 frame = frame->down;
2833 if (frame->torp == origrp) {
2835 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2837 replace_deactivate_replacement_points(origcode);
2842 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2846 /* build the new execution state */
2848 replace_build_execution_state(ss, es);
2850 #if !defined(NDEBUG)
2851 /* continue execution after patched machine code, if testing mode enabled */
2853 if (opt_TestReplacement)
2854 es->pc += REPLACEMENT_PATCH_SIZE;
2857 /* release dump area */
2863 /* replace_me_wrapper **********************************************************
2865 This function is called by the signal handler. It determines if there
2866 is an active replacement point pending at the given PC and returns
2869 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2872 pc...............the program counter that triggered the replacement.
2873 context..........the context (machine state) to which the
2874 replacement should be applied.
2877 context..........the context after replacement finished.
2880 true.............replacement done, everything went ok
2881 false............no replacement done, context unchanged
2883 *******************************************************************************/
2885 bool replace_me_wrapper(u1 *pc, void *context)
2889 executionstate_t es;
2891 /* search the codeinfo for the given PC */
2893 code = code_find_codeinfo_for_pc(pc);
2896 /* search for a replacement point at the given PC */
2898 rp = replace_find_replacement_point_for_pc(code, pc);
2900 /* check if the replacement point belongs to given PC and is active */
2902 if ((rp != NULL) && (rp->pc == pc) && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
2904 /* set codeinfo pointer in execution state */
2908 /* read execution state from current context */
2910 md_replace_executionstate_read(&es, context);
2912 DOLOG( printf("REPLACEMENT READ: ");
2913 replace_executionstate_println(&es); );
2915 /* do the actual replacement */
2917 replace_me(rp, &es);
2919 /* write execution state to current context */
2921 md_replace_executionstate_write(&es, context);
2923 DOLOG( printf("REPLACEMENT WRITE: ");
2924 replace_executionstate_println(&es); );
2926 /* new code is entered after returning */
2928 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2936 /******************************************************************************/
2937 /* NOTE: Stuff specific to the exact GC is below. */
2938 /******************************************************************************/
2940 #if defined(ENABLE_GC_CACAO)
2941 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
2943 stackframeinfo_t *sfi;
2944 executionstate_t *es;
2947 /* get the stackframeinfo of this thread */
2948 assert(thread == THREADOBJECT);
2949 sfi = STACKFRAMEINFO;
2951 /* create the execution state */
2952 es = DNEW(executionstate_t);
2955 es->pv = 0; /* since we are in a native, PV is invalid! */
2956 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
2958 /* we assume we are in a native (no replacement point)! */
2959 ss = replace_recover_source_state(NULL, sfi, es);
2961 /* map the sourcestate using the identity mapping */
2962 replace_map_source_state_identity(ss);
2964 /* remember executionstate and sourcestate for this thread */
2965 GC_EXECUTIONSTATE = es;
2966 GC_SOURCESTATE = ss;
2970 #if defined(ENABLE_GC_CACAO)
2971 void replace_gc_into_native(threadobject *thread)
2973 executionstate_t *es;
2976 /* get the executionstate and sourcestate for the given thread */
2977 es = GC_EXECUTIONSTATE;
2978 ss = GC_SOURCESTATE;
2980 /* rebuild the stack of the given thread */
2981 replace_build_execution_state(ss, es);
2986 /******************************************************************************/
2987 /* NOTE: No important code below. */
2988 /******************************************************************************/
2991 /* statistics *****************************************************************/
2993 #if defined(REPLACE_STATISTICS)
2994 static void print_freq(FILE *file,int *array,int limit)
2999 for (i=0; i<limit; ++i)
3001 sum += array[limit];
3002 for (i=0; i<limit; ++i) {
3004 fprintf(file," %3d: %8d (cum %3d%%)\n",
3005 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3007 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3009 #endif /* defined(REPLACE_STATISTICS) */
3012 #if defined(REPLACE_STATISTICS)
3014 #define REPLACE_PRINT_DIST(name, array) \
3015 printf(" " name " distribution:\n"); \
3016 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3018 void replace_print_statistics(void)
3020 printf("replacement statistics:\n");
3021 printf(" # of replacements: %d\n", stat_replacements);
3022 printf(" # of frames: %d\n", stat_frames);
3023 printf(" # of recompilations: %d\n", stat_recompile);
3024 printf(" patched static calls:%d\n", stat_staticpatch);
3025 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3026 printf(" unrolled calls: %d\n", stat_unroll_call);
3027 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3028 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3029 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3030 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3031 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3032 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3033 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3034 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3035 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3036 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3038 printf(" # of methods: %d\n", stat_methods);
3039 printf(" # of replacement points: %d\n", stat_rploints);
3040 printf(" # of regallocs: %d\n", stat_regallocs);
3041 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3042 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3043 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3047 #endif /* defined(REPLACE_STATISTICS) */
3050 #if defined(REPLACE_STATISTICS)
3051 static void replace_statistics_source_frame(sourceframe_t *frame)
3060 for (i=0; i<frame->javalocalcount; ++i) {
3061 switch (frame->javalocaltype[i]) {
3062 case TYPE_ADR: adr++; break;
3063 case TYPE_RET: ret++; break;
3064 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3065 case TYPE_VOID: vd++; break;
3070 REPLACE_COUNT_DIST(stat_dist_locals, n);
3071 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3072 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3073 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3074 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3075 adr = ret = prim = n = 0;
3076 for (i=0; i<frame->javastackdepth; ++i) {
3077 switch (frame->javastacktype[i]) {
3078 case TYPE_ADR: adr++; break;
3079 case TYPE_RET: ret++; break;
3080 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3084 REPLACE_COUNT_DIST(stat_dist_stack, n);
3085 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3086 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3087 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3089 #endif /* defined(REPLACE_STATISTICS) */
3092 /* debugging helpers **********************************************************/
3094 /* replace_replacement_point_println *******************************************
3096 Print replacement point info.
3099 rp...............the replacement point to print
3101 *******************************************************************************/
3103 #if !defined(NDEBUG)
3105 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3107 static char *replace_type_str[] = {
3117 void replace_replacement_point_println(rplpoint *rp, int depth)
3123 printf("(rplpoint *)NULL\n");
3127 for (j=0; j<depth; ++j)
3130 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3131 rp->id, (void*)rp,rp->pc,rp->callsize,
3132 replace_type_str[rp->type]);
3133 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3135 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3136 printf(" COUNTDOWN");
3137 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3139 printf(" parent:%p\n", (void*)rp->parent);
3140 for (j=0; j<depth; ++j)
3142 printf("ra:%d = [", rp->regalloccount);
3144 for (j=0; j<rp->regalloccount; ++j) {
3147 index = rp->regalloc[j].index;
3149 case RPLALLOC_STACK: printf("S"); break;
3150 case RPLALLOC_PARAM: printf("P"); break;
3151 case RPLALLOC_SYNC : printf("Y"); break;
3152 default: printf("%d", index);
3154 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3155 if (rp->regalloc[j].type == TYPE_RET) {
3156 printf("ret(L%03d)", rp->regalloc[j].regoff);
3159 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3164 for (j=0; j<depth; ++j)
3167 method_print(rp->method);
3171 #endif /* !defined(NDEBUG) */
3174 /* replace_show_replacement_points *********************************************
3176 Print replacement point info.
3179 code.............codeinfo whose replacement points should be printed.
3181 *******************************************************************************/
3183 #if !defined(NDEBUG)
3184 void replace_show_replacement_points(codeinfo *code)
3192 printf("(codeinfo *)NULL\n");
3196 printf("\treplacement points: %d\n",code->rplpointcount);
3198 printf("\ttotal allocations : %d\n",code->regalloccount);
3199 printf("\tsaved int regs : %d\n",code->savedintcount);
3200 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3201 #if defined(HAS_ADDRESS_REGISTER_FILE)
3202 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3204 printf("\tmemuse : %d\n",code->memuse);
3208 for (i=0; i<code->rplpointcount; ++i) {
3209 rp = code->rplpoints + i;
3212 parent = rp->parent;
3215 parent = parent->parent;
3217 replace_replacement_point_println(rp, depth);
3223 /* replace_executionstate_println **********************************************
3225 Print execution state
3228 es...............the execution state to print
3230 *******************************************************************************/
3232 #if !defined(NDEBUG)
3233 void replace_executionstate_println(executionstate_t *es)
3241 printf("(executionstate_t *)NULL\n");
3245 printf("executionstate_t:\n");
3246 printf("\tpc = %p",(void*)es->pc);
3247 printf(" sp = %p",(void*)es->sp);
3248 printf(" pv = %p\n",(void*)es->pv);
3249 #if defined(ENABLE_DISASSEMBLER)
3250 for (i=0; i<INT_REG_CNT; ++i) {
3255 #if SIZEOF_VOID_P == 8
3256 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3258 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3263 for (i=0; i<FLT_REG_CNT; ++i) {
3268 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3272 # if defined(HAS_ADDRESS_REGISTER_FILE)
3273 for (i=0; i<ADR_REG_CNT; ++i) {
3278 printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
3285 sp = (stackslot_t *) es->sp;
3290 methoddesc *md = es->code->m->parseddesc;
3291 slots = es->code->stackframesize;
3292 extraslots = 1 + md->memuse;
3299 printf("\tstack slots(+%d) at sp:", extraslots);
3300 for (i=0; i<slots+extraslots; ++i) {
3303 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3304 #ifdef HAS_4BYTE_STACKSLOT
3305 printf("%08lx",(unsigned long)*sp++);
3307 printf("%016llx",(unsigned long long)*sp++);
3309 printf("%c", (i >= slots) ? ')' : ' ');
3314 printf("\tcode: %p", (void*)es->code);
3315 if (es->code != NULL) {
3316 printf(" stackframesize=%d ", es->code->stackframesize);
3317 method_print(es->code->m);
3325 #if !defined(NDEBUG)
3326 static void java_value_print(s4 type, replace_val_t value)
3331 printf("%016llx",(unsigned long long) value.l);
3333 if (type < 0 || type > TYPE_RET)
3334 printf(" <INVALID TYPE:%d>", type);
3336 printf(" %s", show_jit_type_names[type]);
3338 if (type == TYPE_ADR && value.a != NULL) {
3341 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3343 if (obj->vftbl->class == class_java_lang_String) {
3345 u = javastring_toutf(obj, false);
3346 utf_display_printable_ascii(u);
3350 else if (type == TYPE_INT) {
3351 printf(" %ld", (long) value.i);
3353 else if (type == TYPE_LNG) {
3354 printf(" %lld", (long long) value.l);
3356 else if (type == TYPE_FLT) {
3357 printf(" %f", value.f);
3359 else if (type == TYPE_DBL) {
3360 printf(" %f", value.d);
3363 #endif /* !defined(NDEBUG) */
3366 #if !defined(NDEBUG)
3367 void replace_source_frame_println(sourceframe_t *frame)
3372 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3373 printf("\tNATIVE\n");
3374 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3375 printf("\tnativepc: %p\n", frame->nativepc);
3376 printf("\tframesize: %d\n", frame->nativeframesize);
3379 for (i=0; i<INT_REG_CNT; ++i) {
3380 if (nregdescint[i] == REG_SAV)
3381 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3385 for (i=0; i<FLT_REG_CNT; ++i) {
3386 if (nregdescfloat[i] == REG_SAV)
3387 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3395 method_println(frame->method);
3396 printf("\tid: %d\n", frame->id);
3397 printf("\ttype: %s\n", replace_type_str[frame->type]);
3400 if (frame->instance.a) {
3401 printf("\tinstance: ");
3402 java_value_print(TYPE_ADR, frame->instance);
3406 if (frame->javalocalcount) {
3407 printf("\tlocals (%d):\n",frame->javalocalcount);
3408 for (i=0; i<frame->javalocalcount; ++i) {
3409 t = frame->javalocaltype[i];
3410 if (t == TYPE_VOID) {
3411 printf("\tlocal[ %2d] = void\n",i);
3414 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3415 java_value_print(t, frame->javalocals[i]);
3422 if (frame->javastackdepth) {
3423 printf("\tstack (depth %d):\n",frame->javastackdepth);
3424 for (i=0; i<frame->javastackdepth; ++i) {
3425 t = frame->javastacktype[i];
3426 if (t == TYPE_VOID) {
3427 printf("\tstack[%2d] = void", i);
3430 printf("\tstack[%2d] = ",i);
3431 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3438 if (frame->syncslotcount) {
3439 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3440 for (i=0; i<frame->syncslotcount; ++i) {
3441 printf("\tslot[%2d] = ",i);
3442 #ifdef HAS_4BYTE_STACKSLOT
3443 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3445 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3451 if (frame->fromcode) {
3452 printf("\tfrom %p ", (void*)frame->fromcode);
3453 method_println(frame->fromcode->m);
3455 if (frame->tocode) {
3456 printf("\tto %p ", (void*)frame->tocode);
3457 method_println(frame->tocode->m);
3460 if (frame->fromrp) {
3461 printf("\tfrom replacement point:\n");
3462 replace_replacement_point_println(frame->fromrp, 2);
3465 printf("\tto replacement point:\n");
3466 replace_replacement_point_println(frame->torp, 2);
3471 #endif /* !defined(NDEBUG) */
3474 /* replace_sourcestate_println *************************************************
3479 ss...............the source state to print
3481 *******************************************************************************/
3483 #if !defined(NDEBUG)
3484 void replace_sourcestate_println(sourcestate_t *ss)
3487 sourceframe_t *frame;
3490 printf("(sourcestate_t *)NULL\n");
3494 printf("sourcestate_t:\n");
3496 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3497 printf(" frame %d:\n", i);
3498 replace_source_frame_println(frame);
3504 /* replace_sourcestate_println_short *******************************************
3506 Print a compact representation of the given source state.
3509 ss...............the source state to print
3511 *******************************************************************************/
3513 #if !defined(NDEBUG)
3514 void replace_sourcestate_println_short(sourcestate_t *ss)
3516 sourceframe_t *frame;
3518 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3521 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3522 printf("NATIVE (pc %p size %d) ",
3523 (void*)frame->nativepc, frame->nativeframesize);
3524 replace_stackframeinfo_println(frame->sfi);
3529 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3532 printf("%s", replace_type_str[frame->fromrp->type]);
3534 if (frame->torp && frame->torp->type != frame->fromrp->type)
3535 printf("->%s", replace_type_str[frame->torp->type]);
3537 if (frame->tocode != frame->fromcode)
3538 printf(" (%p->%p/%d) ",
3539 (void*) frame->fromcode, (void*) frame->tocode,
3542 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3544 method_println(frame->method);
3549 #if !defined(NDEBUG)
3550 static void replace_stackframeinfo_println(stackframeinfo_t *sfi)
3552 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3553 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3554 (void*)sfi->ra, (void*)sfi->xpc);
3557 method_println(sfi->code->m);
3564 * These are local overrides for various environment variables in Emacs.
3565 * Please do not remove this and leave it at the end of the file, where
3566 * Emacs will automagically detect them.
3567 * ---------------------------------------------------------------------
3570 * indent-tabs-mode: t
3574 * vim:noexpandtab:sw=4:ts=4: