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_t *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 /* in instance methods, we may need a rplpoint at the method entry */
434 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
435 if (!(m->flags & ACC_STATIC)) {
436 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
442 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
444 /* iterate over the basic block list to find replacement points */
449 javalocals = DMNEW(s4, jd->maxlocals);
451 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
455 if (bptr->flags < BBFINISHED)
458 /* get info about this block */
461 iinfo = bptr->inlineinfo;
463 /* initialize javalocals at the start of this block */
465 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
467 /* iterate over the instructions */
470 iend = iptr + bptr->icount;
474 for (; iptr != iend; ++iptr) {
476 #if defined(ENABLE_GC_CACAO)
478 md = iptr->sx.s23.s3.bte->md;
480 COUNT_javalocals(javalocals, m, alloccount);
481 alloccount += iptr->s1.argcount;
483 alloccount -= iinfo->throughcount;
487 case ICMD_INVOKESTATIC:
488 case ICMD_INVOKESPECIAL:
489 case ICMD_INVOKEVIRTUAL:
490 case ICMD_INVOKEINTERFACE:
491 INSTRUCTION_GET_METHODDESC(iptr, md);
493 COUNT_javalocals(javalocals, m, alloccount);
494 alloccount += iptr->s1.argcount;
496 alloccount -= iinfo->throughcount;
504 stack_javalocals_store(iptr, javalocals);
518 case ICMD_INLINE_START:
519 iinfo = iptr->sx.s23.s3.inlineinfo;
522 COUNT_javalocals(javalocals, m, alloccount);
523 alloccount += iinfo->stackvarscount;
524 if (iinfo->synclocal != UNUSED)
528 /* javalocals may be set at next block start, or now */
529 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
532 case ICMD_INLINE_BODY:
533 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
535 jl = iinfo->javalocals_start;
537 /* get the javalocals from the following block start */
539 jl = bptr->next->javalocals;
542 COUNT_javalocals(jl, m, alloccount);
545 case ICMD_INLINE_END:
546 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
547 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
548 iinfo = iptr->sx.s23.s3.inlineinfo;
550 if (iinfo->javalocals_end)
551 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
552 iinfo = iinfo->parent;
556 if (iptr == bptr->iinstr)
558 } /* end instruction loop */
560 /* create replacement points at targets of backward branches */
561 /* We only need the replacement point there, if there is no */
562 /* replacement point inside the block. */
564 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
565 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
566 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
570 if (test > startcount) {
571 /* we don't need an extra rplpoint */
572 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
576 alloccount += bptr->indepth;
577 if (bptr->inlineinfo)
578 alloccount -= bptr->inlineinfo->throughcount;
580 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
584 } /* end basicblock loop */
586 /* if no points were found, there's nothing to do */
591 /* allocate replacement point array and allocation array */
593 rplpoints = MNEW(rplpoint, count);
594 regalloc = MNEW(rplalloc, alloccount);
597 /* initialize replacement point structs */
601 /* XXX try to share code with the counting loop! */
603 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
606 if (bptr->flags < BBFINISHED)
609 /* get info about this block */
612 iinfo = bptr->inlineinfo;
614 /* initialize javalocals at the start of this block */
616 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
618 /* create replacement points at targets of backward branches */
620 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
622 i = (iinfo) ? iinfo->throughcount : 0;
623 replace_create_replacement_point(jd, iinfo, rp++,
624 bptr->type, bptr->iinstr, &ra,
625 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
627 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
628 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
631 /* iterate over the instructions */
634 iend = iptr + bptr->icount;
636 for (; iptr != iend; ++iptr) {
638 #if defined(ENABLE_GC_CACAO)
640 md = iptr->sx.s23.s3.bte->md;
642 i = (iinfo) ? iinfo->throughcount : 0;
643 replace_create_replacement_point(jd, iinfo, rp++,
644 RPLPOINT_TYPE_CALL, iptr, &ra,
645 javalocals, iptr->sx.s23.s2.args,
646 iptr->s1.argcount - i,
651 case ICMD_INVOKESTATIC:
652 case ICMD_INVOKESPECIAL:
653 case ICMD_INVOKEVIRTUAL:
654 case ICMD_INVOKEINTERFACE:
655 INSTRUCTION_GET_METHODDESC(iptr, md);
657 i = (iinfo) ? iinfo->throughcount : 0;
658 replace_create_replacement_point(jd, iinfo, rp++,
659 RPLPOINT_TYPE_CALL, iptr, &ra,
660 javalocals, iptr->sx.s23.s2.args,
661 iptr->s1.argcount - i,
670 stack_javalocals_store(iptr, javalocals);
678 replace_create_replacement_point(jd, iinfo, rp++,
679 RPLPOINT_TYPE_RETURN, iptr, &ra,
680 NULL, &(iptr->s1.varindex), 1, 0);
684 replace_create_replacement_point(jd, iinfo, rp++,
685 RPLPOINT_TYPE_RETURN, iptr, &ra,
689 case ICMD_INLINE_START:
690 iinfo = replace_create_inline_start_replacement_point(
691 jd, rp++, iptr, &ra, javalocals);
693 /* javalocals may be set at next block start, or now */
694 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
697 case ICMD_INLINE_BODY:
698 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
700 jl = iinfo->javalocals_start;
702 /* get the javalocals from the following block start */
704 jl = bptr->next->javalocals;
706 /* create a non-trappable rplpoint */
707 replace_create_replacement_point(jd, iinfo, rp++,
708 RPLPOINT_TYPE_BODY, iptr, &ra,
710 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
713 case ICMD_INLINE_END:
714 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
715 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
716 iinfo = iptr->sx.s23.s3.inlineinfo;
718 if (iinfo->javalocals_end)
719 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
720 iinfo = iinfo->parent;
723 } /* end instruction loop */
724 } /* end basicblock loop */
726 assert((rp - rplpoints) == count);
727 assert((ra - regalloc) == alloccount);
729 /* store the data in the codeinfo */
731 code->rplpoints = rplpoints;
732 code->rplpointcount = count;
733 code->regalloc = regalloc;
734 code->regalloccount = alloccount;
735 code->globalcount = 0;
736 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
737 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
738 #if defined(HAS_ADDRESS_REGISTER_FILE)
739 code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
741 code->memuse = rd->memuse;
742 code->stackframesize = jd->cd->stackframesize;
744 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
745 REPLACE_COUNT_INC(stat_regallocs, alloccount);
747 /* everything alright */
753 /* replace_free_replacement_points *********************************************
755 Free memory used by replacement points.
758 code.............codeinfo whose replacement points should be freed.
760 *******************************************************************************/
762 void replace_free_replacement_points(codeinfo *code)
767 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
770 MFREE(code->regalloc,rplalloc,code->regalloccount);
772 code->rplpoints = NULL;
773 code->rplpointcount = 0;
774 code->regalloc = NULL;
775 code->regalloccount = 0;
776 code->globalcount = 0;
780 /******************************************************************************/
781 /* PART II: Activating / deactivating replacement points */
782 /******************************************************************************/
785 /* replace_activate_replacement_points *****************************************
787 Activate the replacement points of the given compilation unit. When this
788 function returns, the replacement points are "armed", so each thread
789 reaching one of the points will enter the replacement mechanism.
792 code.............codeinfo of which replacement points should be
794 mappable.........if true, only mappable replacement points are
797 *******************************************************************************/
799 void replace_activate_replacement_points(codeinfo *code, bool mappable)
806 assert(code->savedmcode == NULL);
808 /* count trappable replacement points */
811 i = code->rplpointcount;
812 rp = code->rplpoints;
814 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
817 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
823 /* allocate buffer for saved machine code */
825 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
826 code->savedmcode = savedmcode;
827 savedmcode += count * REPLACEMENT_PATCH_SIZE;
829 /* activate trappable replacement points */
830 /* (in reverse order to handle overlapping points within basic blocks) */
832 i = code->rplpointcount;
833 rp = code->rplpoints + i;
835 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
837 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
840 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
843 DOLOG( printf("activate replacement point:\n");
844 replace_replacement_point_println(rp, 1); fflush(stdout); );
846 savedmcode -= REPLACEMENT_PATCH_SIZE;
848 #if defined(ENABLE_JIT)
849 # if defined(ENABLE_DISASSEMBLER)
850 DOLOG( printf("\tinstruction before: ");
851 disassinstr(rp->pc); fflush(stdout); );
854 md_patch_replacement_point(rp->pc, savedmcode, false);
856 # if defined(ENABLE_DISASSEMBLER)
857 DOLOG( printf("\tinstruction after : ");
858 disassinstr(rp->pc); fflush(stdout); );
862 rp->flags |= RPLPOINT_FLAG_ACTIVE;
865 assert(savedmcode == code->savedmcode);
869 /* replace_deactivate_replacement_points ***************************************
871 Deactivate a replacement points in the given compilation unit.
872 When this function returns, the replacement points will be "un-armed",
873 that is a each thread reaching a point will just continue normally.
876 code.............the compilation unit
878 *******************************************************************************/
880 void replace_deactivate_replacement_points(codeinfo *code)
887 if (code->savedmcode == NULL) {
888 /* disarm countdown points by patching the branches */
890 i = code->rplpointcount;
891 rp = code->rplpoints;
893 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
894 == RPLPOINT_FLAG_COUNTDOWN)
897 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
904 assert(code->savedmcode != NULL);
905 savedmcode = code->savedmcode;
907 /* de-activate each trappable replacement point */
909 i = code->rplpointcount;
910 rp = code->rplpoints;
913 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
918 DOLOG( printf("deactivate replacement point:\n");
919 replace_replacement_point_println(rp, 1); fflush(stdout); );
921 #if defined(ENABLE_JIT)
922 # if defined(ENABLE_DISASSEMBLER)
923 DOLOG( printf("\tinstruction before: ");
924 disassinstr(rp->pc); fflush(stdout); );
927 md_patch_replacement_point(rp->pc, savedmcode, true);
929 # if defined(ENABLE_DISASSEMBLER)
930 DOLOG( printf("\tinstruction before: ");
931 disassinstr(rp->pc); fflush(stdout); );
935 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
937 savedmcode += REPLACEMENT_PATCH_SIZE;
940 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
942 /* free saved machine code */
944 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
945 code->savedmcode = NULL;
949 /******************************************************************************/
950 /* PART III: The replacement mechanism */
951 /******************************************************************************/
954 /* replace_read_value **********************************************************
956 Read a value with the given allocation from the execution state.
959 es...............execution state
960 ra...............allocation
961 javaval..........where to put the value
964 *javaval.........the value
966 *******************************************************************************/
968 static void replace_read_value(executionstate_t *es,
970 replace_val_t *javaval)
972 if (ra->flags & INMEMORY) {
973 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
974 #ifdef HAS_4BYTE_STACKSLOT
975 if (IS_2_WORD_TYPE(ra->type)) {
976 javaval->l = *(u8*)(es->sp + ra->regoff);
980 javaval->p = *(ptrint*)(es->sp + ra->regoff);
981 #ifdef HAS_4BYTE_STACKSLOT
986 /* allocated register */
987 if (IS_FLT_DBL_TYPE(ra->type)) {
988 javaval->d = es->fltregs[ra->regoff];
990 if (ra->type == TYPE_FLT)
991 javaval->f = javaval->d;
993 #if defined(HAS_ADDRESS_REGISTER_FILE)
994 else if (IS_ADR_TYPE(ra->type)) {
995 javaval->p = es->adrregs[ra->regoff];
999 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1000 if (ra->type == TYPE_LNG) {
1001 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
1002 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
1005 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
1006 javaval->p = es->intregs[ra->regoff];
1012 /* replace_write_value *********************************************************
1014 Write a value to the given allocation in the execution state.
1017 es...............execution state
1018 ra...............allocation
1019 *javaval.........the value
1021 *******************************************************************************/
1023 static void replace_write_value(executionstate_t *es,
1025 replace_val_t *javaval)
1027 if (ra->flags & INMEMORY) {
1028 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1029 #ifdef HAS_4BYTE_STACKSLOT
1030 if (IS_2_WORD_TYPE(ra->type)) {
1031 *(u8*)(es->sp + ra->regoff) = javaval->l;
1035 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1036 #ifdef HAS_4BYTE_STACKSLOT
1041 /* allocated register */
1044 es->fltregs[ra->regoff] = (double) javaval->f;
1047 es->fltregs[ra->regoff] = javaval->d;
1049 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1051 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1052 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1055 #if defined(HAS_ADDRESS_REGISTER_FILE)
1057 es->adrregs[ra->regoff] = javaval->p;
1060 es->intregs[ra->regoff] = javaval->p;
1066 /* replace_new_sourceframe *****************************************************
1068 Allocate a new source frame and insert it at the front of the frame list.
1071 ss...............the source state
1074 ss->frames.......set to new frame (the new head of the frame list).
1077 returns the new frame
1079 *******************************************************************************/
1081 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1083 sourceframe_t *frame;
1085 frame = DNEW(sourceframe_t);
1086 MZERO(frame, sourceframe_t, 1);
1088 frame->down = ss->frames;
1095 /* replace_read_executionstate *************************************************
1097 Read a source frame from the given executions state.
1098 The new source frame is pushed to the front of the frame list of the
1102 rp...............replacement point at which `es` was taken
1103 es...............execution state
1104 ss...............the source state to add the source frame to
1105 topframe.........true, if the first (top-most) source frame on the
1109 *ss..............the source state with the newly created source frame
1112 *******************************************************************************/
1114 static s4 replace_normalize_type_map[] = {
1115 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1116 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1117 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1118 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1119 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1120 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1121 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1125 static void replace_read_executionstate(rplpoint *rp,
1126 executionstate_t *es,
1135 sourceframe_t *frame;
1138 stackslot_t *basesp;
1140 code = code_find_codeinfo_for_pc(rp->pc);
1142 topslot = TOP_IS_NORMAL;
1146 sp = (stackslot_t *) es->sp;
1148 /* in some cases the top stack slot is passed in REG_ITMP1 */
1150 if (rp->type == BBTYPE_EXH) {
1151 topslot = TOP_IS_IN_ITMP1;
1154 /* calculate base stack pointer */
1156 basesp = sp + code->stackframesize;
1158 /* create the source frame */
1160 frame = replace_new_sourceframe(ss);
1161 frame->method = rp->method;
1163 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1164 frame->type = replace_normalize_type_map[rp->type];
1166 frame->fromcode = code;
1168 /* read local variables */
1170 count = m->maxlocals;
1171 frame->javalocalcount = count;
1172 frame->javalocals = DMNEW(replace_val_t, count);
1173 frame->javalocaltype = DMNEW(u1, count);
1175 /* mark values as undefined */
1176 for (i=0; i<count; ++i) {
1177 #if !defined(NDEBUG)
1178 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1180 frame->javalocaltype[i] = TYPE_VOID;
1183 /* some entries in the intregs array are not meaningful */
1184 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1185 #if !defined(NDEBUG)
1186 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1188 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1190 #endif /* !defined(NDEBUG) */
1192 /* read javalocals */
1194 count = rp->regalloccount;
1197 while (count && (i = ra->index) >= 0) {
1198 assert(i < m->maxlocals);
1199 frame->javalocaltype[i] = ra->type;
1200 if (ra->type == TYPE_RET)
1201 frame->javalocals[i].i = ra->regoff;
1203 replace_read_value(es, ra, frame->javalocals + i);
1208 /* read instance, if this is the first rplpoint */
1210 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1211 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1213 /* we are at the start of the method body, so if local 0 is set, */
1214 /* it is the instance. */
1215 if (frame->javalocaltype[0] == TYPE_ADR)
1216 frame->instance = frame->javalocals[0];
1221 md = rp->method->parseddesc;
1223 assert(md->paramcount >= 1);
1224 instra.type = TYPE_ADR;
1225 instra.regoff = md->params[0].regoff;
1226 if (md->params[0].inmemory) {
1227 instra.flags = INMEMORY;
1228 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1233 replace_read_value(es, &instra, &(frame->instance));
1236 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1238 /* read stack slots */
1240 frame->javastackdepth = count;
1241 frame->javastack = DMNEW(replace_val_t, count);
1242 frame->javastacktype = DMNEW(u1, count);
1244 #if !defined(NDEBUG)
1245 /* mark values as undefined */
1246 for (i=0; i<count; ++i) {
1247 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1248 frame->javastacktype[i] = TYPE_VOID;
1250 #endif /* !defined(NDEBUG) */
1254 /* the first stack slot is special in SBR and EXH blocks */
1256 if (topslot == TOP_IS_ON_STACK) {
1259 assert(ra->index == RPLALLOC_STACK);
1260 assert(ra->type == TYPE_ADR);
1261 frame->javastack[i].p = sp[-1];
1262 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1267 else if (topslot == TOP_IS_IN_ITMP1) {
1270 assert(ra->index == RPLALLOC_STACK);
1271 assert(ra->type == TYPE_ADR);
1272 frame->javastack[i].p = es->intregs[REG_ITMP1];
1273 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1278 else if (topslot == TOP_IS_VOID) {
1281 assert(ra->index == RPLALLOC_STACK);
1282 frame->javastack[i].l = 0;
1283 frame->javastacktype[i] = TYPE_VOID;
1289 /* read remaining stack slots */
1291 for (; count--; ra++) {
1292 if (ra->index == RPLALLOC_SYNC) {
1293 assert(rp->type == RPLPOINT_TYPE_INLINE);
1295 /* only read synchronization slots when traversing an inline point */
1298 sourceframe_t *calleeframe = frame->down;
1299 assert(calleeframe);
1300 assert(calleeframe->syncslotcount == 0);
1301 assert(calleeframe->syncslots == NULL);
1303 calleeframe->syncslotcount = 1;
1304 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1305 replace_read_value(es,ra,calleeframe->syncslots);
1308 frame->javastackdepth--;
1312 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1314 /* do not read parameters of calls down the call chain */
1316 if (!topframe && ra->index == RPLALLOC_PARAM) {
1317 frame->javastackdepth--;
1320 if (ra->type == TYPE_RET)
1321 frame->javastack[i].i = ra->regoff;
1323 replace_read_value(es,ra,frame->javastack + i);
1324 frame->javastacktype[i] = ra->type;
1331 /* replace_write_executionstate ************************************************
1333 Pop a source frame from the front of the frame list of the given source state
1334 and write its values into the execution state.
1337 rp...............replacement point for which execution state should be
1339 es...............the execution state to modify
1340 ss...............the given source state
1341 topframe.........true, if this is the last (top-most) source frame to be
1345 *es..............the execution state derived from the source state
1347 *******************************************************************************/
1349 static void replace_write_executionstate(rplpoint *rp,
1350 executionstate_t *es,
1359 sourceframe_t *frame;
1362 stackslot_t *basesp;
1364 code = code_find_codeinfo_for_pc(rp->pc);
1366 topslot = TOP_IS_NORMAL;
1368 /* pop a source frame */
1372 ss->frames = frame->down;
1374 /* calculate stack pointer */
1376 sp = (stackslot_t *) es->sp;
1378 basesp = sp + code->stackframesize;
1380 /* in some cases the top stack slot is passed in REG_ITMP1 */
1382 if (rp->type == BBTYPE_EXH) {
1383 topslot = TOP_IS_IN_ITMP1;
1386 /* write javalocals */
1389 count = rp->regalloccount;
1391 while (count && (i = ra->index) >= 0) {
1392 assert(i < m->maxlocals);
1393 assert(i < frame->javalocalcount);
1394 assert(ra->type == frame->javalocaltype[i]);
1395 if (ra->type == TYPE_RET) {
1396 /* XXX assert that it matches this rplpoint */
1399 replace_write_value(es, ra, frame->javalocals + i);
1404 /* write stack slots */
1408 /* the first stack slot is special in SBR and EXH blocks */
1410 if (topslot == TOP_IS_ON_STACK) {
1413 assert(ra->index == RPLALLOC_STACK);
1414 assert(i < frame->javastackdepth);
1415 assert(frame->javastacktype[i] == TYPE_ADR);
1416 sp[-1] = frame->javastack[i].p;
1421 else if (topslot == TOP_IS_IN_ITMP1) {
1424 assert(ra->index == RPLALLOC_STACK);
1425 assert(i < frame->javastackdepth);
1426 assert(frame->javastacktype[i] == TYPE_ADR);
1427 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1432 else if (topslot == TOP_IS_VOID) {
1435 assert(ra->index == RPLALLOC_STACK);
1436 assert(i < frame->javastackdepth);
1437 assert(frame->javastacktype[i] == TYPE_VOID);
1443 /* write remaining stack slots */
1445 for (; count--; ra++) {
1446 if (ra->index == RPLALLOC_SYNC) {
1447 assert(rp->type == RPLPOINT_TYPE_INLINE);
1449 /* only write synchronization slots when traversing an inline point */
1452 assert(frame->down);
1453 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1454 assert(frame->down->syncslots != NULL);
1456 replace_write_value(es,ra,frame->down->syncslots);
1461 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1463 /* do not write parameters of calls down the call chain */
1465 if (!topframe && ra->index == RPLALLOC_PARAM) {
1469 assert(i < frame->javastackdepth);
1470 assert(ra->type == frame->javastacktype[i]);
1471 if (ra->type == TYPE_RET) {
1472 /* XXX assert that it matches this rplpoint */
1475 replace_write_value(es,ra,frame->javastack + i);
1487 /* replace_pop_activation_record ***********************************************
1489 Peel a stack frame from the execution state.
1491 *** This function imitates the effects of the method epilog ***
1492 *** and returning from the method call. ***
1495 es...............execution state
1496 frame............source frame, receives synchronization slots
1499 *es..............the execution state after popping the stack frame
1501 *******************************************************************************/
1503 u1* replace_pop_activation_record(executionstate_t *es,
1504 sourceframe_t *frame)
1512 stackslot_t *basesp;
1518 /* read the return address */
1520 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1521 if (code_is_leafmethod(es->code))
1522 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1525 ra = md_stacktrace_get_returnaddress(es->sp,
1526 SIZE_OF_STACKSLOT * es->code->stackframesize);
1528 DOLOG( printf("RA = %p\n", (void*)ra); );
1532 /* calculate the base of the stack frame */
1534 sp = (stackslot_t *) es->sp;
1535 basesp = sp + es->code->stackframesize;
1537 /* read slots used for synchronization */
1539 assert(frame->syncslotcount == 0);
1540 assert(frame->syncslots == NULL);
1541 count = code_get_sync_slot_count(es->code);
1542 frame->syncslotcount = count;
1543 frame->syncslots = DMNEW(replace_val_t, count);
1544 for (i=0; i<count; ++i) {
1545 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1548 /* restore return address, if part of frame */
1550 #if defined(REPLACE_RA_TOP_OF_FRAME)
1551 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1552 if (!code_is_leafmethod(es->code))
1554 es->intregs[REPLACE_REG_RA] = *--basesp;
1555 #endif /* REPLACE_RA_TOP_OF_FRAME */
1557 #if defined(REPLACE_RA_LINKAGE_AREA)
1558 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1559 if (!code_is_leafmethod(es->code))
1561 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1562 #endif /* REPLACE_RA_LINKAGE_AREA */
1564 /* restore saved int registers */
1567 for (i=0; i<es->code->savedintcount; ++i) {
1568 while (nregdescint[--reg] != REG_SAV)
1570 es->intregs[reg] = *--basesp;
1573 /* restore saved flt registers */
1577 for (i=0; i<es->code->savedfltcount; ++i) {
1578 while (nregdescfloat[--reg] != REG_SAV)
1580 basesp -= STACK_SLOTS_PER_FLOAT;
1581 es->fltregs[reg] = *(double*)basesp;
1584 #if defined(HAS_ADDRESS_REGISTER_FILE)
1585 /* restore saved adr registers */
1588 for (i=0; i<es->code->savedadrcount; ++i) {
1589 while (nregdescadr[--reg] != REG_SAV)
1591 es->adrregs[reg] = *--basesp;
1595 /* adjust the stackpointer */
1597 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1599 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1600 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1603 /* Set the new pc. Subtract one so we do not hit the replacement point */
1604 /* of the instruction following the call, if there is one. */
1608 /* find the new codeinfo */
1610 pv = md_codegen_get_pv_from_pc(ra);
1611 DOLOG( printf("PV = %p\n", (void*) pv); );
1613 code = code_get_codeinfo_for_pv(pv);
1614 DOLOG( printf("CODE = %p\n", (void*) code); );
1616 /* return NULL if we reached native code */
1621 /* in debugging mode clobber non-saved registers */
1623 #if !defined(NDEBUG)
1625 for (i=0; i<INT_REG_CNT; ++i)
1626 if ((nregdescint[i] != REG_SAV)
1628 && (i != REPLACE_REG_RA)
1631 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1632 for (i=0; i<FLT_REG_CNT; ++i)
1633 if (nregdescfloat[i] != REG_SAV)
1634 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1635 # if defined(HAS_ADDRESS_REGISTER_FILE)
1636 for (i=0; i<ADR_REG_CNT; ++i)
1637 if (nregdescadr[i] != REG_SAV)
1638 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1640 #endif /* !defined(NDEBUG) */
1642 return (code) ? ra : NULL;
1646 /* replace_patch_method_pointer ************************************************
1648 Patch a method pointer (may be in code, data segment, vftbl, or interface
1652 mpp..............address of the method pointer to patch
1653 entrypoint.......the new entrypoint of the method
1654 kind.............kind of call to patch, used only for debugging
1656 *******************************************************************************/
1658 static void replace_patch_method_pointer(methodptr *mpp,
1659 methodptr entrypoint,
1662 #if !defined(NDEBUG)
1667 DOLOG( printf("patch method pointer from: %p to %p\n",
1668 (void*) *mpp, (void*)entrypoint); );
1670 #if !defined(NDEBUG)
1671 oldcode = code_get_codeinfo_for_pv(*mpp);
1672 newcode = code_get_codeinfo_for_pv(entrypoint);
1674 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1675 method_println(oldcode->m);
1676 printf("\t with %p ", (void*) newcode);
1677 method_println(newcode->m); );
1679 assert(oldcode->m == newcode->m);
1682 /* write the new entrypoint */
1684 *mpp = (methodptr) entrypoint;
1688 /* replace_patch_class *********************************************************
1690 Patch a method in the given class.
1693 vftbl............vftbl of the class
1694 m................the method to patch
1695 oldentrypoint....the old entrypoint to replace
1696 entrypoint.......the new entrypoint
1698 *******************************************************************************/
1700 void replace_patch_class(vftbl_t *vftbl,
1709 /* patch the vftbl of the class */
1711 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1715 /* patch the interface tables */
1717 assert(oldentrypoint);
1719 for (i=0; i < vftbl->interfacetablelength; ++i) {
1720 mpp = vftbl->interfacetable[-i];
1721 mppend = mpp + vftbl->interfacevftbllength[i];
1722 for (; mpp != mppend; ++mpp)
1723 if (*mpp == oldentrypoint) {
1724 replace_patch_method_pointer(mpp, entrypoint, "interface");
1730 /* replace_patch_class_hierarchy ***********************************************
1732 Patch a method in all loaded classes.
1735 m................the method to patch
1736 oldentrypoint....the old entrypoint to replace
1737 entrypoint.......the new entrypoint
1739 *******************************************************************************/
1741 struct replace_patch_data_t {
1747 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1749 vftbl_t *vftbl = c->vftbl;
1752 && vftbl->vftbllength > pd->m->vftblindex
1753 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1754 && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
1756 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1760 void replace_patch_class_hierarchy(methodinfo *m,
1764 struct replace_patch_data_t pd;
1767 pd.oldentrypoint = oldentrypoint;
1768 pd.entrypoint = entrypoint;
1770 DOLOG_SHORT( printf("patching class hierarchy: ");
1771 method_println(m); );
1773 classcache_foreach_loaded_class(
1774 (classcache_foreach_functionptr_t) &replace_patch_callback,
1779 /* replace_patch_future_calls **************************************************
1781 Analyse a call site and depending on the kind of call patch the call, the
1782 virtual function table, or the interface table.
1785 ra...............return address pointing after the call site
1786 callerframe......source frame of the caller
1787 calleeframe......source frame of the callee, must have been mapped
1789 *******************************************************************************/
1791 void replace_patch_future_calls(u1 *ra,
1792 sourceframe_t *callerframe,
1793 sourceframe_t *calleeframe)
1796 methodptr entrypoint;
1797 methodptr oldentrypoint;
1800 codeinfo *calleecode;
1801 methodinfo *calleem;
1806 assert(callerframe->down == calleeframe);
1808 /* get the new codeinfo and the method that shall be entered */
1810 calleecode = calleeframe->tocode;
1813 calleem = calleeframe->method;
1814 assert(calleem == calleecode->m);
1816 entrypoint = (methodptr) calleecode->entrypoint;
1818 /* check if we are at an method entry rplpoint at the innermost frame */
1820 atentry = (calleeframe->down == NULL)
1821 && !(calleem->flags & ACC_STATIC)
1822 && (calleeframe->fromrp->id == 0); /* XXX */
1824 /* get the position to patch, in case it was a statically bound call */
1826 pv = callerframe->fromcode->entrypoint;
1827 patchpos = md_jit_method_patch_address(pv, ra, NULL);
1829 if (patchpos == NULL) {
1830 /* the call was dispatched dynamically */
1832 /* we can only patch such calls if we are at the entry point */
1837 assert((calleem->flags & ACC_STATIC) == 0);
1839 oldentrypoint = calleeframe->fromcode->entrypoint;
1841 /* we need to know the instance */
1843 if (!calleeframe->instance.a) {
1844 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1845 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1851 obj = calleeframe->instance.a;
1854 assert(vftbl->class->vftbl == vftbl);
1856 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1858 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1861 /* the call was statically bound */
1863 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1868 /* replace_push_activation_record **********************************************
1870 Push a stack frame onto the execution state.
1872 *** This function imitates the effects of a call and the ***
1873 *** method prolog of the callee. ***
1876 es...............execution state
1877 rpcall...........the replacement point at the call site
1878 callerframe......source frame of the caller, or NULL for creating the
1880 calleeframe......source frame of the callee, must have been mapped
1883 *es..............the execution state after pushing the stack frame
1885 *******************************************************************************/
1887 void replace_push_activation_record(executionstate_t *es,
1889 sourceframe_t *callerframe,
1890 sourceframe_t *calleeframe)
1895 stackslot_t *basesp;
1898 codeinfo *calleecode;
1901 assert(!rpcall || callerframe);
1902 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1903 assert(!rpcall || rpcall == callerframe->torp);
1904 assert(calleeframe);
1905 assert(!callerframe || calleeframe == callerframe->down);
1907 /* the compilation unit we are entering */
1909 calleecode = calleeframe->tocode;
1912 /* calculate the return address */
1915 ra = rpcall->pc + rpcall->callsize;
1917 ra = es->pc + 1 /* XXX this is ugly */;
1919 /* write the return address */
1921 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1922 es->sp -= SIZE_OF_STACKSLOT;
1924 *((stackslot_t *)es->sp) = (stackslot_t) ra;
1925 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1927 #if defined(REPLACE_REG_RA)
1928 es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1931 /* we move into a new code unit */
1933 es->code = calleecode;
1935 /* set the new pc XXX not needed? */
1937 es->pc = calleecode->entrypoint;
1939 /* build the stackframe */
1941 DOLOG( printf("building stackframe of %d words at %p\n",
1942 calleecode->stackframesize, (void*)es->sp); );
1944 sp = (stackslot_t *) es->sp;
1947 sp -= calleecode->stackframesize;
1950 /* in debug mode, invalidate stack frame first */
1952 /* XXX may not invalidate linkage area used by native code! */
1953 #if !defined(NDEBUG) && 0
1954 for (i=0; i<(basesp - sp); ++i) {
1955 sp[i] = 0xdeaddeadU;
1959 /* save the return address register */
1961 #if defined(REPLACE_RA_TOP_OF_FRAME)
1962 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1963 if (!code_is_leafmethod(calleecode))
1965 *--basesp = (ptrint) ra;
1966 #endif /* REPLACE_RA_TOP_OF_FRAME */
1968 #if defined(REPLACE_RA_LINKAGE_AREA)
1969 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1970 if (!code_is_leafmethod(calleecode))
1972 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1973 #endif /* REPLACE_RA_LINKAGE_AREA */
1975 /* save int registers */
1978 for (i=0; i<calleecode->savedintcount; ++i) {
1979 while (nregdescint[--reg] != REG_SAV)
1981 *--basesp = es->intregs[reg];
1983 /* XXX may not clobber saved regs used by native code! */
1984 #if !defined(NDEBUG) && 0
1985 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1989 /* save flt registers */
1993 for (i=0; i<calleecode->savedfltcount; ++i) {
1994 while (nregdescfloat[--reg] != REG_SAV)
1996 basesp -= STACK_SLOTS_PER_FLOAT;
1997 *(double*)basesp = es->fltregs[reg];
1999 /* XXX may not clobber saved regs used by native code! */
2000 #if !defined(NDEBUG) && 0
2001 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
2005 #if defined(HAS_ADDRESS_REGISTER_FILE)
2006 /* save adr registers */
2009 for (i=0; i<calleecode->savedadrcount; ++i) {
2010 while (nregdescadr[--reg] != REG_SAV)
2012 *--basesp = es->adrregs[reg];
2014 /* XXX may not clobber saved regs used by native code! */
2015 #if !defined(NDEBUG) && 0
2016 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
2021 /* write slots used for synchronization */
2023 count = code_get_sync_slot_count(calleecode);
2024 assert(count == calleeframe->syncslotcount);
2025 for (i=0; i<count; ++i) {
2026 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2031 es->pv = calleecode->entrypoint;
2033 /* redirect future invocations */
2035 if (callerframe && rpcall) {
2036 #if defined(REPLACE_PATCH_ALL)
2037 if (rpcall->type == callerframe->fromrp->type)
2039 if (rpcall == callerframe->fromrp)
2041 replace_patch_future_calls(ra, callerframe, calleeframe);
2046 /* replace_find_replacement_point **********************************************
2048 Find the replacement point in the given code corresponding to the
2049 position given in the source frame.
2052 code.............the codeinfo in which to search the rplpoint
2053 frame............the source frame defining the position to look for
2054 parent...........parent replacement point to match
2057 the replacement point
2059 *******************************************************************************/
2061 rplpoint * replace_find_replacement_point(codeinfo *code,
2062 sourceframe_t *frame,
2075 DOLOG( printf("searching replacement point for:\n");
2076 replace_source_frame_println(frame); );
2080 DOLOG( printf("code = %p\n", (void*)code); );
2082 rp = code->rplpoints;
2083 i = code->rplpointcount;
2085 if (rp->id == frame->id && rp->method == frame->method
2086 && rp->parent == parent
2087 && replace_normalize_type_map[rp->type] == frame->type)
2089 /* check if returnAddresses match */
2090 /* XXX optimize: only do this if JSRs in method */
2091 DOLOG( printf("checking match for:");
2092 replace_replacement_point_println(rp, 1); fflush(stdout); );
2095 for (j = rp->regalloccount; j--; ++ra) {
2096 if (ra->type == TYPE_RET) {
2097 if (ra->index == RPLALLOC_STACK) {
2098 assert(stacki < frame->javastackdepth);
2099 if (frame->javastack[stacki].i != ra->regoff)
2104 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2105 if (frame->javalocals[ra->index].i != ra->regoff)
2118 #if !defined(NDEBUG)
2119 printf("candidate replacement points were:\n");
2120 rp = code->rplpoints;
2121 i = code->rplpointcount;
2123 replace_replacement_point_println(rp, 1);
2127 vm_abort("no matching replacement point found");
2128 return NULL; /* NOT REACHED */
2132 /* replace_find_replacement_point_for_pc ***************************************
2134 Find the nearest replacement point at or before the given PC. The
2135 given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
2136 the replacement point to be found.
2139 code.............compilation unit the PC is in
2140 pc...............the machine code PC
2143 the replacement point found, or
2144 NULL if no replacement point was found
2146 *******************************************************************************/
2148 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2154 DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
2155 method_println(code->m); );
2159 rp = code->rplpoints;
2160 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2161 DOLOG( replace_replacement_point_println(rp, 2); );
2162 if (rp->pc <= pc && rp->pc + rp->callsize >= pc)
2170 /* replace_pop_native_frame ****************************************************
2172 Unroll a native frame in the execution state and create a source frame
2176 es...............current execution state
2177 ss...............the current source state
2178 sfi..............stackframeinfo for the native frame
2181 es...............execution state after unrolling the native frame
2182 ss...............gets the added native source frame
2184 *******************************************************************************/
2186 static void replace_pop_native_frame(executionstate_t *es,
2188 stackframeinfo_t *sfi)
2190 sourceframe_t *frame;
2196 frame = replace_new_sourceframe(ss);
2200 /* remember pc and size of native frame */
2202 frame->nativepc = es->pc;
2203 frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2204 assert(frame->nativeframesize >= 0);
2206 /* remember values of saved registers */
2209 for (i=0; i<INT_REG_CNT; ++i) {
2210 if (nregdescint[i] == REG_SAV)
2211 frame->nativesavint[j++] = es->intregs[i];
2215 for (i=0; i<FLT_REG_CNT; ++i) {
2216 if (nregdescfloat[i] == REG_SAV)
2217 frame->nativesavflt[j++] = es->fltregs[i];
2220 #if defined(HAS_ADDRESS_REGISTER_FILE)
2222 for (i=0; i<ADR_REG_CNT; ++i) {
2223 if (nregdescadr[i] == REG_SAV)
2224 frame->nativesavadr[j++] = es->adrregs[i];
2228 /* restore saved registers */
2230 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2232 for (i=0; i<INT_REG_CNT; ++i) {
2233 if (nregdescint[i] == REG_SAV)
2234 es->intregs[i] = sfi->intregs[j++];
2237 /* XXX we don't have them, yet, in the sfi, so clear them */
2239 for (i=0; i<INT_REG_CNT; ++i) {
2240 if (nregdescint[i] == REG_SAV)
2245 /* XXX we don't have float registers in the sfi, so clear them */
2247 for (i=0; i<FLT_REG_CNT; ++i) {
2248 if (nregdescfloat[i] == REG_SAV)
2249 es->fltregs[i] = 0.0;
2252 #if defined(HAS_ADDRESS_REGISTER_FILE)
2253 # if defined(ENABLE_GC_CACAO)
2255 for (i=0; i<ADR_REG_CNT; ++i) {
2256 if (nregdescadr[i] == REG_SAV)
2257 es->adrregs[i] = sfi->adrregs[j++];
2260 for (i=0; i<ADR_REG_CNT; ++i) {
2261 if (nregdescadr[i] == REG_SAV)
2267 /* restore codeinfo of the native stub */
2269 code = code_get_codeinfo_for_pv(sfi->pv);
2271 /* restore sp, pv, pc and codeinfo of the parent method */
2273 /* XXX michi: use this instead:
2274 es->sp = sfi->sp + code->stackframesize; */
2275 es->sp = sfi->sp + (*(s4 *) (sfi->pv + FrameSize));
2276 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2277 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
2279 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2280 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2281 es->code = code_get_codeinfo_for_pv(es->pv);
2285 /* replace_push_native_frame ***************************************************
2287 Rebuild a native frame onto the execution state and remove its source frame.
2289 Note: The native frame is "rebuild" by setting fields like PC and stack
2290 pointer in the execution state accordingly. Values in the
2291 stackframeinfo may be modified, but the actual stack frame of the
2292 native code is not touched.
2295 es...............current execution state
2296 ss...............the current source state
2299 es...............execution state after re-rolling the native frame
2300 ss...............the native source frame is removed
2302 *******************************************************************************/
2304 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2306 sourceframe_t *frame;
2312 DOLOG( printf("pushing native frame\n"); );
2314 /* remove the frame from the source state */
2318 assert(REPLACE_IS_NATIVE_FRAME(frame));
2320 ss->frames = frame->down;
2322 /* skip sp for the native stub */
2324 es->sp -= (*(s4 *) (frame->sfi->pv + FrameSize));
2325 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2326 es->sp -= SIZE_OF_STACKSLOT; /* skip return address */
2329 /* assert that the native frame has not moved */
2331 assert(es->sp == frame->sfi->sp);
2333 /* update saved registers in the stackframeinfo */
2335 #if defined(ENABLE_GC_CACAO)
2337 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2338 for (i=0; i<INT_REG_CNT; ++i) {
2339 if (nregdescint[i] == REG_SAV)
2340 frame->sfi->intregs[j++] = es->intregs[i];
2343 for (i=0; i<ADR_REG_CNT; ++i) {
2344 if (nregdescadr[i] == REG_SAV)
2345 frame->sfi->adrregs[j++] = es->adrregs[i];
2349 /* XXX leave float registers untouched here */
2352 /* restore saved registers */
2355 for (i=0; i<INT_REG_CNT; ++i) {
2356 if (nregdescint[i] == REG_SAV)
2357 es->intregs[i] = frame->nativesavint[j++];
2361 for (i=0; i<FLT_REG_CNT; ++i) {
2362 if (nregdescfloat[i] == REG_SAV)
2363 es->fltregs[i] = frame->nativesavflt[j++];
2366 #if defined(HAS_ADDRESS_REGISTER_FILE)
2368 for (i=0; i<ADR_REG_CNT; ++i) {
2369 if (nregdescadr[i] == REG_SAV)
2370 es->adrregs[i] = frame->nativesavadr[j++];
2374 /* skip the native frame on the machine stack */
2376 es->sp -= frame->nativeframesize;
2378 /* set the pc the next frame must return to */
2380 es->pc = frame->nativepc;
2384 /* replace_recover_source_state ************************************************
2386 Recover the source state from the given replacement point and execution
2390 rp...............replacement point that has been reached, if any
2391 sfi..............stackframeinfo, if called from native code
2392 es...............execution state at the replacement point rp
2397 *******************************************************************************/
2399 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2400 stackframeinfo_t *sfi,
2401 executionstate_t *es)
2406 #if defined(REPLACE_STATISTICS)
2410 /* create the source frame structure in dump memory */
2412 ss = DNEW(sourcestate_t);
2415 /* each iteration of the loop recovers one source frame */
2422 DOLOG( replace_executionstate_println(es); );
2424 /* if we are not at a replacement point, it is a native frame */
2427 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2430 replace_pop_native_frame(es, ss, sfi);
2433 if (es->code == NULL)
2436 goto after_machine_frame;
2439 /* read the values for this source frame from the execution state */
2441 DOLOG( printf("recovering source state for%s:\n",
2442 (ss->frames == NULL) ? " TOPFRAME" : "");
2443 replace_replacement_point_println(rp, 1); );
2445 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2447 #if defined(ENABLE_VMLOG)
2448 vmlog_cacao_unrol_method(ss->frames->method);
2451 #if defined(REPLACE_STATISTICS)
2452 REPLACE_COUNT(stat_frames);
2454 replace_statistics_source_frame(ss->frames);
2457 /* in locked areas (below native frames), identity map the frame */
2460 ss->frames->torp = ss->frames->fromrp;
2461 ss->frames->tocode = ss->frames->fromcode;
2464 /* unroll to the next (outer) frame */
2467 /* this frame is in inlined code */
2469 DOLOG( printf("INLINED!\n"); );
2473 assert(rp->type == RPLPOINT_TYPE_INLINE);
2474 REPLACE_COUNT(stat_unroll_inline);
2477 /* this frame had been called at machine-level. pop it. */
2479 DOLOG( printf("UNWIND\n"); );
2481 ra = replace_pop_activation_record(es, ss->frames);
2483 DOLOG( printf("REACHED NATIVE CODE\n"); );
2487 #if !defined(ENABLE_GC_CACAO)
2488 break; /* XXX remove to activate native frames */
2493 /* find the replacement point at the call site */
2495 after_machine_frame:
2496 rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2499 vm_abort("could not find replacement point while unrolling call");
2501 DOLOG( printf("found replacement point.\n");
2502 replace_replacement_point_println(rp, 1); );
2504 assert(rp->type == RPLPOINT_TYPE_CALL);
2505 REPLACE_COUNT(stat_unroll_call);
2507 } /* end loop over source frames */
2509 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2515 /* replace_map_source_state ****************************************************
2517 Map each source frame in the given source state to a target replacement
2518 point and compilation unit. If no valid code is available for a source
2519 frame, it is (re)compiled.
2522 ss...............the source state
2525 ss...............the source state, modified: The `torp` and `tocode`
2526 fields of each source frame are set.
2529 true.............everything went ok
2530 false............an exception has been thrown
2532 *******************************************************************************/
2534 static bool replace_map_source_state(sourcestate_t *ss)
2536 sourceframe_t *frame;
2539 rplpoint *parent; /* parent of inlined rplpoint */
2540 #if defined(REPLACE_STATISTICS)
2547 /* iterate over the source frames from outermost to innermost */
2549 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2551 /* XXX skip native frames */
2553 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2558 /* map frames which are not already mapped */
2560 if (frame->tocode) {
2561 code = frame->tocode;
2566 assert(frame->torp == NULL);
2568 if (parent == NULL) {
2569 /* find code for this frame */
2571 #if defined(REPLACE_STATISTICS)
2572 oldcode = frame->method->code;
2574 /* request optimization of hot methods and their callers */
2576 if (frame->method->hitcountdown < 0
2577 || (frame->down && frame->down->method->hitcountdown < 0))
2578 jit_request_optimization(frame->method);
2580 code = jit_get_current_code(frame->method);
2583 return false; /* exception */
2585 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2590 /* map this frame */
2592 rp = replace_find_replacement_point(code, frame, parent);
2594 frame->tocode = code;
2598 if (rp->type == RPLPOINT_TYPE_CALL) {
2611 /* replace_map_source_state_identity *******************************************
2613 Map each source frame in the given source state to the same replacement
2614 point and compilation unit it was derived from. This is mainly used for
2618 ss...............the source state
2621 ss...............the source state, modified: The `torp` and `tocode`
2622 fields of each source frame are set.
2624 *******************************************************************************/
2626 #if defined(ENABLE_GC_CACAO)
2627 static void replace_map_source_state_identity(sourcestate_t *ss)
2629 sourceframe_t *frame;
2631 /* iterate over the source frames from outermost to innermost */
2633 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2635 /* skip native frames */
2637 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2641 /* map frames using the identity mapping */
2643 if (frame->tocode) {
2644 assert(frame->tocode == frame->fromcode);
2645 assert(frame->torp == frame->fromrp);
2647 assert(frame->tocode == NULL);
2648 assert(frame->torp == NULL);
2649 frame->tocode = frame->fromcode;
2650 frame->torp = frame->fromrp;
2657 /* replace_build_execution_state ***********************************************
2659 Build an execution state for the given (mapped) source state.
2661 !!! CAUTION: This function rewrites the machine stack !!!
2663 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2666 ss...............the source state. Must have been mapped by
2667 replace_map_source_state before.
2668 es...............the base execution state on which to build
2671 *es..............the new execution state
2673 *******************************************************************************/
2675 static void replace_build_execution_state(sourcestate_t *ss,
2676 executionstate_t *es)
2679 sourceframe_t *prevframe;
2686 while (ss->frames) {
2688 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2689 prevframe = ss->frames;
2690 replace_push_native_frame(es, ss);
2696 if (parent == NULL) {
2697 /* create a machine-level stack frame */
2699 DOLOG( printf("pushing activation record for:\n");
2700 if (rp) replace_replacement_point_println(rp, 1);
2701 else printf("\tfirst frame\n"); );
2703 replace_push_activation_record(es, rp, prevframe, ss->frames);
2705 DOLOG( replace_executionstate_println(es); );
2708 rp = ss->frames->torp;
2711 DOLOG( printf("creating execution state for%s:\n",
2712 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2713 replace_replacement_point_println(ss->frames->fromrp, 1);
2714 replace_replacement_point_println(rp, 1); );
2716 es->code = ss->frames->tocode;
2717 prevframe = ss->frames;
2719 #if defined(ENABLE_VMLOG)
2720 vmlog_cacao_rerol_method(ss->frames->method);
2723 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2725 DOLOG( replace_executionstate_println(es); );
2727 if (rp->type == RPLPOINT_TYPE_CALL) {
2738 /* replace_me ******************************************************************
2740 This function is called by the signal handler when a thread reaches
2741 a replacement point. `replace_me` must map the execution state to the
2742 target replacement point and let execution continue there.
2744 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2747 rp...............replacement point that has been reached
2748 es...............execution state read by signal handler
2750 *******************************************************************************/
2752 static void replace_me(rplpoint *rp, executionstate_t *es)
2754 stackframeinfo_t *sfi;
2756 sourceframe_t *frame;
2760 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2761 threadobject *thread;
2764 origcode = es->code;
2767 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2768 stat_replacements, (void*)THREADOBJECT,
2770 method_println(es->code->m); );
2772 DOLOG( replace_replacement_point_println(rp, 1); );
2774 REPLACE_COUNT(stat_replacements);
2776 /* mark start of dump memory area */
2778 dumpsize = dump_size();
2780 /* get the stackframeinfo for the current thread */
2782 sfi = STACKFRAMEINFO;
2784 /* recover source state */
2786 ss = replace_recover_source_state(rp, sfi, es);
2788 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2789 /* if there is a collection pending, we assume the replacement point should
2790 suspend this thread */
2794 thread = THREADOBJECT;
2796 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2798 /* map the sourcestate using the identity mapping */
2799 replace_map_source_state_identity(ss);
2801 /* since we enter the same method again, we turn off rps now */
2802 /* XXX michi: can we really do this? what if the rp was active before
2803 we activated it for the gc? */
2804 replace_deactivate_replacement_points(origcode);
2806 /* remember executionstate and sourcestate for this thread */
2807 GC_EXECUTIONSTATE = es;
2808 GC_SOURCESTATE = ss;
2810 /* really suspend this thread now (PC = 0) */
2811 threads_suspend_ack(NULL, NULL);
2813 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2816 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2818 /* map the source state */
2820 if (!replace_map_source_state(ss))
2821 vm_abort("exception during method replacement");
2823 DOLOG( replace_sourcestate_println(ss); );
2825 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2827 #if !defined(NDEBUG)
2828 /* avoid infinite loops by self-replacement, only if not in testing mode */
2830 if (!opt_TestReplacement) {
2833 frame = frame->down;
2835 if (frame->torp == origrp) {
2837 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2839 replace_deactivate_replacement_points(origcode);
2844 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2848 /* build the new execution state */
2850 replace_build_execution_state(ss, es);
2852 #if !defined(NDEBUG)
2853 /* continue execution after patched machine code, if testing mode enabled */
2855 if (opt_TestReplacement)
2856 es->pc += REPLACEMENT_PATCH_SIZE;
2859 /* release dump area */
2861 dump_release(dumpsize);
2865 /* replace_me_wrapper **********************************************************
2867 This function is called by the signal handler. It determines if there
2868 is an active replacement point pending at the given PC and returns
2871 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2874 pc...............the program counter that triggered the replacement.
2875 context..........the context (machine state) to which the
2876 replacement should be applied.
2879 context..........the context after replacement finished.
2882 true.............replacement done, everything went ok
2883 false............no replacement done, context unchanged
2885 *******************************************************************************/
2887 bool replace_me_wrapper(u1 *pc, void *context)
2891 executionstate_t es;
2893 /* search the codeinfo for the given PC */
2895 code = code_find_codeinfo_for_pc(pc);
2898 /* search for a replacement point at the given PC */
2900 rp = replace_find_replacement_point_for_pc(code, pc);
2902 /* check if the replacement point belongs to given PC and is active */
2904 if ((rp != NULL) && (rp->pc == pc) && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
2906 /* set codeinfo pointer in execution state */
2910 /* read execution state from current context */
2912 md_replace_executionstate_read(&es, context);
2914 DOLOG( printf("REPLACEMENT READ: ");
2915 replace_executionstate_println(&es); );
2917 /* do the actual replacement */
2919 replace_me(rp, &es);
2921 /* write execution state to current context */
2923 md_replace_executionstate_write(&es, context);
2925 DOLOG( printf("REPLACEMENT WRITE: ");
2926 replace_executionstate_println(&es); );
2928 /* new code is entered after returning */
2930 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2938 /******************************************************************************/
2939 /* NOTE: Stuff specific to the exact GC is below. */
2940 /******************************************************************************/
2942 #if defined(ENABLE_GC_CACAO)
2943 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
2945 stackframeinfo_t *sfi;
2946 executionstate_t *es;
2949 /* get the stackframeinfo of this thread */
2950 assert(thread == THREADOBJECT);
2951 sfi = STACKFRAMEINFO;
2953 /* create the execution state */
2954 es = DNEW(executionstate_t);
2957 es->pv = 0; /* since we are in a native, PV is invalid! */
2958 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
2960 /* we assume we are in a native (no replacement point)! */
2961 ss = replace_recover_source_state(NULL, sfi, es);
2963 /* map the sourcestate using the identity mapping */
2964 replace_map_source_state_identity(ss);
2966 /* remember executionstate and sourcestate for this thread */
2967 GC_EXECUTIONSTATE = es;
2968 GC_SOURCESTATE = ss;
2972 #if defined(ENABLE_GC_CACAO)
2973 void replace_gc_into_native(threadobject *thread)
2975 executionstate_t *es;
2978 /* get the executionstate and sourcestate for the given thread */
2979 es = GC_EXECUTIONSTATE;
2980 ss = GC_SOURCESTATE;
2982 /* rebuild the stack of the given thread */
2983 replace_build_execution_state(ss, es);
2988 /******************************************************************************/
2989 /* NOTE: No important code below. */
2990 /******************************************************************************/
2993 /* statistics *****************************************************************/
2995 #if defined(REPLACE_STATISTICS)
2996 static void print_freq(FILE *file,int *array,int limit)
3001 for (i=0; i<limit; ++i)
3003 sum += array[limit];
3004 for (i=0; i<limit; ++i) {
3006 fprintf(file," %3d: %8d (cum %3d%%)\n",
3007 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3009 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3011 #endif /* defined(REPLACE_STATISTICS) */
3014 #if defined(REPLACE_STATISTICS)
3016 #define REPLACE_PRINT_DIST(name, array) \
3017 printf(" " name " distribution:\n"); \
3018 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3020 void replace_print_statistics(void)
3022 printf("replacement statistics:\n");
3023 printf(" # of replacements: %d\n", stat_replacements);
3024 printf(" # of frames: %d\n", stat_frames);
3025 printf(" # of recompilations: %d\n", stat_recompile);
3026 printf(" patched static calls:%d\n", stat_staticpatch);
3027 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3028 printf(" unrolled calls: %d\n", stat_unroll_call);
3029 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3030 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3031 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3032 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3033 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3034 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3035 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3036 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3037 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3038 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3040 printf(" # of methods: %d\n", stat_methods);
3041 printf(" # of replacement points: %d\n", stat_rploints);
3042 printf(" # of regallocs: %d\n", stat_regallocs);
3043 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3044 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3045 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3049 #endif /* defined(REPLACE_STATISTICS) */
3052 #if defined(REPLACE_STATISTICS)
3053 static void replace_statistics_source_frame(sourceframe_t *frame)
3062 for (i=0; i<frame->javalocalcount; ++i) {
3063 switch (frame->javalocaltype[i]) {
3064 case TYPE_ADR: adr++; break;
3065 case TYPE_RET: ret++; break;
3066 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3067 case TYPE_VOID: vd++; break;
3072 REPLACE_COUNT_DIST(stat_dist_locals, n);
3073 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3074 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3075 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3076 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3077 adr = ret = prim = n = 0;
3078 for (i=0; i<frame->javastackdepth; ++i) {
3079 switch (frame->javastacktype[i]) {
3080 case TYPE_ADR: adr++; break;
3081 case TYPE_RET: ret++; break;
3082 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3086 REPLACE_COUNT_DIST(stat_dist_stack, n);
3087 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3088 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3089 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3091 #endif /* defined(REPLACE_STATISTICS) */
3094 /* debugging helpers **********************************************************/
3096 /* replace_replacement_point_println *******************************************
3098 Print replacement point info.
3101 rp...............the replacement point to print
3103 *******************************************************************************/
3105 #if !defined(NDEBUG)
3107 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3109 static char *replace_type_str[] = {
3119 void replace_replacement_point_println(rplpoint *rp, int depth)
3125 printf("(rplpoint *)NULL\n");
3129 for (j=0; j<depth; ++j)
3132 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3133 rp->id, (void*)rp,rp->pc,rp->callsize,
3134 replace_type_str[rp->type]);
3135 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3137 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3138 printf(" COUNTDOWN");
3139 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3141 printf(" parent:%p\n", (void*)rp->parent);
3142 for (j=0; j<depth; ++j)
3144 printf("ra:%d = [", rp->regalloccount);
3146 for (j=0; j<rp->regalloccount; ++j) {
3149 index = rp->regalloc[j].index;
3151 case RPLALLOC_STACK: printf("S"); break;
3152 case RPLALLOC_PARAM: printf("P"); break;
3153 case RPLALLOC_SYNC : printf("Y"); break;
3154 default: printf("%d", index);
3156 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3157 if (rp->regalloc[j].type == TYPE_RET) {
3158 printf("ret(L%03d)", rp->regalloc[j].regoff);
3161 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3166 for (j=0; j<depth; ++j)
3169 method_print(rp->method);
3173 #endif /* !defined(NDEBUG) */
3176 /* replace_show_replacement_points *********************************************
3178 Print replacement point info.
3181 code.............codeinfo whose replacement points should be printed.
3183 *******************************************************************************/
3185 #if !defined(NDEBUG)
3186 void replace_show_replacement_points(codeinfo *code)
3194 printf("(codeinfo *)NULL\n");
3198 printf("\treplacement points: %d\n",code->rplpointcount);
3200 printf("\ttotal allocations : %d\n",code->regalloccount);
3201 printf("\tsaved int regs : %d\n",code->savedintcount);
3202 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3203 #if defined(HAS_ADDRESS_REGISTER_FILE)
3204 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3206 printf("\tmemuse : %d\n",code->memuse);
3210 for (i=0; i<code->rplpointcount; ++i) {
3211 rp = code->rplpoints + i;
3214 parent = rp->parent;
3217 parent = parent->parent;
3219 replace_replacement_point_println(rp, depth);
3225 /* replace_executionstate_println **********************************************
3227 Print execution state
3230 es...............the execution state to print
3232 *******************************************************************************/
3234 #if !defined(NDEBUG)
3235 void replace_executionstate_println(executionstate_t *es)
3243 printf("(executionstate_t *)NULL\n");
3247 printf("executionstate_t:\n");
3248 printf("\tpc = %p",(void*)es->pc);
3249 printf(" sp = %p",(void*)es->sp);
3250 printf(" pv = %p\n",(void*)es->pv);
3251 #if defined(ENABLE_DISASSEMBLER)
3252 for (i=0; i<INT_REG_CNT; ++i) {
3257 #if SIZEOF_VOID_P == 8
3258 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3260 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3265 for (i=0; i<FLT_REG_CNT; ++i) {
3270 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3274 # if defined(HAS_ADDRESS_REGISTER_FILE)
3275 for (i=0; i<ADR_REG_CNT; ++i) {
3280 printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
3287 sp = (stackslot_t *) es->sp;
3292 methoddesc *md = es->code->m->parseddesc;
3293 slots = es->code->stackframesize;
3294 extraslots = 1 + md->memuse;
3301 printf("\tstack slots(+%d) at sp:", extraslots);
3302 for (i=0; i<slots+extraslots; ++i) {
3305 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3306 #ifdef HAS_4BYTE_STACKSLOT
3307 printf("%08lx",(unsigned long)*sp++);
3309 printf("%016llx",(unsigned long long)*sp++);
3311 printf("%c", (i >= slots) ? ')' : ' ');
3316 printf("\tcode: %p", (void*)es->code);
3317 if (es->code != NULL) {
3318 printf(" stackframesize=%d ", es->code->stackframesize);
3319 method_print(es->code->m);
3327 #if !defined(NDEBUG)
3328 static void java_value_print(s4 type, replace_val_t value)
3333 printf("%016llx",(unsigned long long) value.l);
3335 if (type < 0 || type > TYPE_RET)
3336 printf(" <INVALID TYPE:%d>", type);
3338 printf(" %s", show_jit_type_names[type]);
3340 if (type == TYPE_ADR && value.a != NULL) {
3343 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3345 if (obj->vftbl->class == class_java_lang_String) {
3347 u = javastring_toutf(obj, false);
3348 utf_display_printable_ascii(u);
3352 else if (type == TYPE_INT) {
3353 printf(" %ld", (long) value.i);
3355 else if (type == TYPE_LNG) {
3356 printf(" %lld", (long long) value.l);
3358 else if (type == TYPE_FLT) {
3359 printf(" %f", value.f);
3361 else if (type == TYPE_DBL) {
3362 printf(" %f", value.d);
3365 #endif /* !defined(NDEBUG) */
3368 #if !defined(NDEBUG)
3369 void replace_source_frame_println(sourceframe_t *frame)
3374 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3375 printf("\tNATIVE\n");
3376 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3377 printf("\tnativepc: %p\n", frame->nativepc);
3378 printf("\tframesize: %d\n", frame->nativeframesize);
3381 for (i=0; i<INT_REG_CNT; ++i) {
3382 if (nregdescint[i] == REG_SAV)
3383 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3387 for (i=0; i<FLT_REG_CNT; ++i) {
3388 if (nregdescfloat[i] == REG_SAV)
3389 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3397 method_println(frame->method);
3398 printf("\tid: %d\n", frame->id);
3399 printf("\ttype: %s\n", replace_type_str[frame->type]);
3402 if (frame->instance.a) {
3403 printf("\tinstance: ");
3404 java_value_print(TYPE_ADR, frame->instance);
3408 if (frame->javalocalcount) {
3409 printf("\tlocals (%d):\n",frame->javalocalcount);
3410 for (i=0; i<frame->javalocalcount; ++i) {
3411 t = frame->javalocaltype[i];
3412 if (t == TYPE_VOID) {
3413 printf("\tlocal[ %2d] = void\n",i);
3416 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3417 java_value_print(t, frame->javalocals[i]);
3424 if (frame->javastackdepth) {
3425 printf("\tstack (depth %d):\n",frame->javastackdepth);
3426 for (i=0; i<frame->javastackdepth; ++i) {
3427 t = frame->javastacktype[i];
3428 if (t == TYPE_VOID) {
3429 printf("\tstack[%2d] = void", i);
3432 printf("\tstack[%2d] = ",i);
3433 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3440 if (frame->syncslotcount) {
3441 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3442 for (i=0; i<frame->syncslotcount; ++i) {
3443 printf("\tslot[%2d] = ",i);
3444 #ifdef HAS_4BYTE_STACKSLOT
3445 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3447 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3453 if (frame->fromcode) {
3454 printf("\tfrom %p ", (void*)frame->fromcode);
3455 method_println(frame->fromcode->m);
3457 if (frame->tocode) {
3458 printf("\tto %p ", (void*)frame->tocode);
3459 method_println(frame->tocode->m);
3462 if (frame->fromrp) {
3463 printf("\tfrom replacement point:\n");
3464 replace_replacement_point_println(frame->fromrp, 2);
3467 printf("\tto replacement point:\n");
3468 replace_replacement_point_println(frame->torp, 2);
3473 #endif /* !defined(NDEBUG) */
3476 /* replace_sourcestate_println *************************************************
3481 ss...............the source state to print
3483 *******************************************************************************/
3485 #if !defined(NDEBUG)
3486 void replace_sourcestate_println(sourcestate_t *ss)
3489 sourceframe_t *frame;
3492 printf("(sourcestate_t *)NULL\n");
3496 printf("sourcestate_t:\n");
3498 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3499 printf(" frame %d:\n", i);
3500 replace_source_frame_println(frame);
3506 /* replace_sourcestate_println_short *******************************************
3508 Print a compact representation of the given source state.
3511 ss...............the source state to print
3513 *******************************************************************************/
3515 #if !defined(NDEBUG)
3516 void replace_sourcestate_println_short(sourcestate_t *ss)
3518 sourceframe_t *frame;
3520 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3523 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3524 printf("NATIVE (pc %p size %d) ",
3525 (void*)frame->nativepc, frame->nativeframesize);
3526 replace_stackframeinfo_println(frame->sfi);
3531 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3534 printf("%s", replace_type_str[frame->fromrp->type]);
3536 if (frame->torp && frame->torp->type != frame->fromrp->type)
3537 printf("->%s", replace_type_str[frame->torp->type]);
3539 if (frame->tocode != frame->fromcode)
3540 printf(" (%p->%p/%d) ",
3541 (void*) frame->fromcode, (void*) frame->tocode,
3544 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3546 method_println(frame->method);
3551 #if !defined(NDEBUG)
3552 static void replace_stackframeinfo_println(stackframeinfo_t *sfi)
3554 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3555 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3556 (void*)sfi->ra, (void*)sfi->xpc);
3559 method_println(sfi->code->m);
3566 * These are local overrides for various environment variables in Emacs.
3567 * Please do not remove this and leave it at the end of the file, where
3568 * Emacs will automagically detect them.
3569 * ---------------------------------------------------------------------
3572 * indent-tabs-mode: t
3576 * vim:noexpandtab:sw=4:ts=4: