1 /* src/vm/jit/replace.c - on-stack replacement of methods
3 Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
36 #if defined(ENABLE_GC_CACAO)
37 # include "mm/cacao-gc/gc.h"
40 #include "mm/memory.h"
42 #include "threads/threads-common.h"
44 #include "toolbox/logging.h"
46 #include "vm/stringlocal.h"
48 #include "vm/jit/abi.h"
49 #include "vm/jit/asmpart.h"
50 #include "vm/jit/disass.h"
51 #include "vm/jit/jit.h"
52 #include "vm/jit/md.h"
53 #include "vm/jit/methodheader.h"
54 #include "vm/jit/replace.h"
55 #include "vm/jit/show.h"
56 #include "vm/jit/stack.h"
58 #include "vmcore/options.h"
59 #include "vmcore/classcache.h"
62 #define REPLACE_PATCH_DYNAMIC_CALL
63 /*#define REPLACE_PATCH_ALL*/
65 #if defined(ENABLE_VMLOG)
66 #include <vmlog_cacao.h>
69 /*** architecture-dependent configuration *************************************/
71 /* first unset the macros (default) */
72 #undef REPLACE_RA_BETWEEN_FRAMES
73 #undef REPLACE_RA_TOP_OF_FRAME
74 #undef REPLACE_RA_LINKAGE_AREA
75 #undef REPLACE_LEAFMETHODS_RA_REGISTER
78 /* i386, x86_64 and m68k */
79 #if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
80 #define REPLACE_RA_BETWEEN_FRAMES
82 #elif defined(__ALPHA__)
83 #define REPLACE_RA_TOP_OF_FRAME
84 #define REPLACE_LEAFMETHODS_RA_REGISTER
85 #define REPLACE_REG_RA REG_RA
87 #elif defined(__POWERPC__)
88 #define REPLACE_RA_LINKAGE_AREA
89 #define REPLACE_LEAFMETHODS_RA_REGISTER
90 #define REPLACE_REG_RA REG_ITMP3 /* the execution state has the LR in itmp3 */
92 #elif defined(__S390__)
93 #define REPLACE_RA_TOP_OF_FRAME
94 #define REPLACE_REG_RA REG_ITMP3
98 /*** configuration of native stack slot size **********************************/
100 /* XXX this should be in md-abi.h files, probably */
102 #if defined(HAS_4BYTE_STACKSLOT)
103 #define SIZE_OF_STACKSLOT 4
104 #define STACK_SLOTS_PER_FLOAT 2
105 typedef u4 stackslot_t;
107 #define SIZE_OF_STACKSLOT 8
108 #define STACK_SLOTS_PER_FLOAT 1
109 typedef u8 stackslot_t;
113 /*** debugging ****************************************************************/
116 static void java_value_print(s4 type, replace_val_t value);
117 static void replace_stackframeinfo_println(stackframeinfo *sfi);
121 #define DOLOG(code) do{ if (opt_TraceReplacement > 1) { code; } } while(0)
122 #define DOLOG_SHORT(code) do{ if (opt_TraceReplacement > 0) { code; } } while(0)
125 #define DOLOG_SHORT(code)
129 /*** statistics ***************************************************************/
131 #define REPLACE_STATISTICS
133 #if defined(REPLACE_STATISTICS)
135 static int stat_replacements = 0;
136 static int stat_frames = 0;
137 static int stat_recompile = 0;
138 static int stat_staticpatch = 0;
139 static int stat_unroll_inline = 0;
140 static int stat_unroll_call = 0;
141 static int stat_dist_frames[20] = { 0 };
142 static int stat_dist_locals[20] = { 0 };
143 static int stat_dist_locals_adr[10] = { 0 };
144 static int stat_dist_locals_prim[10] = { 0 };
145 static int stat_dist_locals_ret[10] = { 0 };
146 static int stat_dist_locals_void[10] = { 0 };
147 static int stat_dist_stack[10] = { 0 };
148 static int stat_dist_stack_adr[10] = { 0 };
149 static int stat_dist_stack_prim[10] = { 0 };
150 static int stat_dist_stack_ret[10] = { 0 };
151 static int stat_methods = 0;
152 static int stat_rploints = 0;
153 static int stat_regallocs = 0;
154 static int stat_dist_method_rplpoints[20] = { 0 };
156 #define REPLACE_COUNT(cnt) (cnt)++
157 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
158 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
160 #define REPLACE_COUNT_DIST(array, val) \
162 int limit = (sizeof(array) / sizeof(int)) - 1; \
163 if ((val) < (limit)) (array)[val]++; \
164 else (array)[limit]++; \
167 static void replace_statistics_source_frame(sourceframe_t *frame);
171 #define REPLACE_COUNT(cnt)
172 #define REPLACE_COUNT_IF(cnt, cond)
173 #define REPLACE_COUNT_INC(cnt, inc)
174 #define REPLACE_COUNT_DIST(array, val)
176 #endif /* defined(REPLACE_STATISTICS) */
179 /*** constants used internally ************************************************/
181 #define TOP_IS_NORMAL 0
182 #define TOP_IS_ON_STACK 1
183 #define TOP_IS_IN_ITMP1 2
184 #define TOP_IS_VOID 3
187 /******************************************************************************/
188 /* PART I: Creating / freeing replacement points */
189 /******************************************************************************/
192 /* replace_create_replacement_point ********************************************
194 Create a replacement point.
197 jd...............current jitdata
198 iinfo............inlining info for the current position
199 rp...............pre-allocated (uninitialized) rplpoint
200 type.............RPLPOINT_TYPE constant
201 iptr.............current instruction
202 *pra.............current rplalloc pointer
203 javalocals.......the javalocals at the current point
204 stackvars........the stack variables at the current point
205 stackdepth.......the stack depth at the current point
206 paramcount.......number of parameters at the start of stackvars
209 *rpa.............points to the next free rplalloc
211 *******************************************************************************/
213 static void replace_create_replacement_point(jitdata *jd,
214 insinfo_inline *iinfo,
231 REPLACE_COUNT(stat_rploints);
233 rp->method = (iinfo) ? iinfo->method : jd->m;
234 rp->pc = NULL; /* set by codegen */
235 rp->callsize = 0; /* set by codegen */
239 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
241 /* XXX unify these two fields */
242 rp->parent = (iinfo) ? iinfo->rp : NULL;
244 /* store local allocation info of javalocals */
247 for (i = 0; i < rp->method->maxlocals; ++i) {
248 index = javalocals[i];
255 ra->flags = v->flags & (INMEMORY);
256 ra->regoff = v->vv.regoff;
260 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
268 /* store allocation info of java stack vars */
270 for (i = 0; i < stackdepth; ++i) {
271 v = VAR(stackvars[i]);
272 ra->flags = v->flags & (INMEMORY);
273 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
275 /* XXX how to handle locals on the stack containing returnAddresses? */
276 if (v->type == TYPE_RET) {
277 assert(stackvars[i] >= jd->localcount);
278 ra->regoff = v->vv.retaddr->nr;
281 ra->regoff = v->vv.regoff;
285 /* total number of allocations */
287 rp->regalloccount = ra - rp->regalloc;
293 /* replace_create_inline_start_replacement_point *******************************
295 Create an INLINE_START replacement point.
298 jd...............current jitdata
299 rp...............pre-allocated (uninitialized) rplpoint
300 iptr.............current instruction
301 *pra.............current rplalloc pointer
302 javalocals.......the javalocals at the current point
305 *rpa.............points to the next free rplalloc
308 the insinfo_inline * for the following inlined body
310 *******************************************************************************/
312 static insinfo_inline * replace_create_inline_start_replacement_point(
319 insinfo_inline *calleeinfo;
322 calleeinfo = iptr->sx.s23.s3.inlineinfo;
326 replace_create_replacement_point(jd, calleeinfo->parent, rp,
327 RPLPOINT_TYPE_INLINE, iptr, pra,
329 calleeinfo->stackvars, calleeinfo->stackvarscount,
330 calleeinfo->paramcount);
332 if (calleeinfo->synclocal != UNUSED) {
334 ra->index = RPLALLOC_SYNC;
335 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
336 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
346 /* replace_create_replacement_points *******************************************
348 Create the replacement points for the given code.
351 jd...............current jitdata, must not have any replacement points
354 code->rplpoints.......set to the list of replacement points
355 code->rplpointcount...number of replacement points
356 code->regalloc........list of allocation info
357 code->regalloccount...total length of allocation info list
358 code->globalcount.....number of global allocations at the
359 start of code->regalloc
362 true.............everything ok
363 false............an exception has been thrown
365 *******************************************************************************/
367 #define CLEAR_javalocals(array, method) \
369 for (i=0; i<(method)->maxlocals; ++i) \
370 (array)[i] = UNUSED; \
373 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
375 if ((array) != NULL) \
376 MCOPY((dest), (array), s4, (method)->maxlocals); \
378 CLEAR_javalocals((dest), (method)); \
381 #define COUNT_javalocals(array, method, counter) \
383 for (i=0; i<(method)->maxlocals; ++i) \
384 if ((array)[i] != UNUSED) \
388 bool replace_create_replacement_points(jitdata *jd)
406 insinfo_inline *iinfo;
409 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
413 REPLACE_COUNT(stat_methods);
415 /* get required compiler data */
420 /* assert that we wont overwrite already allocated data */
424 assert(code->rplpoints == NULL);
425 assert(code->rplpointcount == 0);
426 assert(code->regalloc == NULL);
427 assert(code->regalloccount == 0);
428 assert(code->globalcount == 0);
432 /* set codeinfo flags */
434 code_flag_leafmethod(code);
436 /* in instance methods, we may need a rplpoint at the method entry */
438 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
439 if (!(m->flags & ACC_STATIC)) {
440 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
446 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
448 /* iterate over the basic block list to find replacement points */
453 javalocals = DMNEW(s4, jd->maxlocals);
455 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
459 if (bptr->flags < BBFINISHED)
462 /* get info about this block */
465 iinfo = bptr->inlineinfo;
467 /* initialize javalocals at the start of this block */
469 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
471 /* iterate over the instructions */
474 iend = iptr + bptr->icount;
478 for (; iptr != iend; ++iptr) {
480 #if defined(ENABLE_GC_CACAO)
482 md = iptr->sx.s23.s3.bte->md;
484 COUNT_javalocals(javalocals, m, alloccount);
485 alloccount += iptr->s1.argcount;
487 alloccount -= iinfo->throughcount;
491 case ICMD_INVOKESTATIC:
492 case ICMD_INVOKESPECIAL:
493 case ICMD_INVOKEVIRTUAL:
494 case ICMD_INVOKEINTERFACE:
495 INSTRUCTION_GET_METHODDESC(iptr, md);
497 COUNT_javalocals(javalocals, m, alloccount);
498 alloccount += iptr->s1.argcount;
500 alloccount -= iinfo->throughcount;
508 stack_javalocals_store(iptr, javalocals);
522 case ICMD_INLINE_START:
523 iinfo = iptr->sx.s23.s3.inlineinfo;
526 COUNT_javalocals(javalocals, m, alloccount);
527 alloccount += iinfo->stackvarscount;
528 if (iinfo->synclocal != UNUSED)
532 /* javalocals may be set at next block start, or now */
533 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
536 case ICMD_INLINE_BODY:
537 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
539 jl = iinfo->javalocals_start;
541 /* get the javalocals from the following block start */
543 jl = bptr->next->javalocals;
546 COUNT_javalocals(jl, m, alloccount);
549 case ICMD_INLINE_END:
550 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
551 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
552 iinfo = iptr->sx.s23.s3.inlineinfo;
554 if (iinfo->javalocals_end)
555 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
556 iinfo = iinfo->parent;
560 if (iptr == bptr->iinstr)
562 } /* end instruction loop */
564 /* create replacement points at targets of backward branches */
565 /* We only need the replacement point there, if there is no */
566 /* replacement point inside the block. */
568 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
569 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
570 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
574 if (test > startcount) {
575 /* we don't need an extra rplpoint */
576 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
580 alloccount += bptr->indepth;
581 if (bptr->inlineinfo)
582 alloccount -= bptr->inlineinfo->throughcount;
584 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
588 } /* end basicblock loop */
590 /* if no points were found, there's nothing to do */
595 /* allocate replacement point array and allocation array */
597 rplpoints = MNEW(rplpoint, count);
598 regalloc = MNEW(rplalloc, alloccount);
601 /* initialize replacement point structs */
605 /* XXX try to share code with the counting loop! */
607 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
610 if (bptr->flags < BBFINISHED)
613 /* get info about this block */
616 iinfo = bptr->inlineinfo;
618 /* initialize javalocals at the start of this block */
620 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
622 /* create replacement points at targets of backward branches */
624 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
626 i = (iinfo) ? iinfo->throughcount : 0;
627 replace_create_replacement_point(jd, iinfo, rp++,
628 bptr->type, bptr->iinstr, &ra,
629 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
631 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
632 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
635 /* iterate over the instructions */
638 iend = iptr + bptr->icount;
640 for (; iptr != iend; ++iptr) {
642 #if defined(ENABLE_GC_CACAO)
644 md = iptr->sx.s23.s3.bte->md;
646 i = (iinfo) ? iinfo->throughcount : 0;
647 replace_create_replacement_point(jd, iinfo, rp++,
648 RPLPOINT_TYPE_CALL, iptr, &ra,
649 javalocals, iptr->sx.s23.s2.args,
650 iptr->s1.argcount - i,
655 case ICMD_INVOKESTATIC:
656 case ICMD_INVOKESPECIAL:
657 case ICMD_INVOKEVIRTUAL:
658 case ICMD_INVOKEINTERFACE:
659 INSTRUCTION_GET_METHODDESC(iptr, md);
661 i = (iinfo) ? iinfo->throughcount : 0;
662 replace_create_replacement_point(jd, iinfo, rp++,
663 RPLPOINT_TYPE_CALL, iptr, &ra,
664 javalocals, iptr->sx.s23.s2.args,
665 iptr->s1.argcount - i,
674 stack_javalocals_store(iptr, javalocals);
682 replace_create_replacement_point(jd, iinfo, rp++,
683 RPLPOINT_TYPE_RETURN, iptr, &ra,
684 NULL, &(iptr->s1.varindex), 1, 0);
688 replace_create_replacement_point(jd, iinfo, rp++,
689 RPLPOINT_TYPE_RETURN, iptr, &ra,
693 case ICMD_INLINE_START:
694 iinfo = replace_create_inline_start_replacement_point(
695 jd, rp++, iptr, &ra, javalocals);
697 /* javalocals may be set at next block start, or now */
698 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
701 case ICMD_INLINE_BODY:
702 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
704 jl = iinfo->javalocals_start;
706 /* get the javalocals from the following block start */
708 jl = bptr->next->javalocals;
710 /* create a non-trappable rplpoint */
711 replace_create_replacement_point(jd, iinfo, rp++,
712 RPLPOINT_TYPE_BODY, iptr, &ra,
714 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
717 case ICMD_INLINE_END:
718 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
719 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
720 iinfo = iptr->sx.s23.s3.inlineinfo;
722 if (iinfo->javalocals_end)
723 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
724 iinfo = iinfo->parent;
727 } /* end instruction loop */
728 } /* end basicblock loop */
730 assert((rp - rplpoints) == count);
731 assert((ra - regalloc) == alloccount);
733 /* store the data in the codeinfo */
735 code->rplpoints = rplpoints;
736 code->rplpointcount = count;
737 code->regalloc = regalloc;
738 code->regalloccount = alloccount;
739 code->globalcount = 0;
740 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
741 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
742 #if defined(HAS_ADDRESS_REGISTER_FILE)
743 code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
745 code->memuse = rd->memuse;
746 code->stackframesize = jd->cd->stackframesize;
748 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
749 REPLACE_COUNT_INC(stat_regallocs, alloccount);
751 /* everything alright */
757 /* replace_free_replacement_points *********************************************
759 Free memory used by replacement points.
762 code.............codeinfo whose replacement points should be freed.
764 *******************************************************************************/
766 void replace_free_replacement_points(codeinfo *code)
771 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
774 MFREE(code->regalloc,rplalloc,code->regalloccount);
776 code->rplpoints = NULL;
777 code->rplpointcount = 0;
778 code->regalloc = NULL;
779 code->regalloccount = 0;
780 code->globalcount = 0;
784 /******************************************************************************/
785 /* PART II: Activating / deactivating replacement points */
786 /******************************************************************************/
789 /* replace_activate_replacement_points *****************************************
791 Activate the replacement points of the given compilation unit. When this
792 function returns, the replacement points are "armed", so each thread
793 reaching one of the points will enter the replacement mechanism.
796 code.............codeinfo of which replacement points should be
798 mappable.........if true, only mappable replacement points are
801 *******************************************************************************/
803 void replace_activate_replacement_points(codeinfo *code, bool mappable)
810 assert(code->savedmcode == NULL);
812 /* count trappable replacement points */
815 i = code->rplpointcount;
816 rp = code->rplpoints;
818 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
821 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
827 /* allocate buffer for saved machine code */
829 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
830 code->savedmcode = savedmcode;
831 savedmcode += count * REPLACEMENT_PATCH_SIZE;
833 /* activate trappable replacement points */
834 /* (in reverse order to handle overlapping points within basic blocks) */
836 i = code->rplpointcount;
837 rp = code->rplpoints + i;
839 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
841 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
844 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
847 DOLOG( printf("activate replacement point:\n");
848 replace_replacement_point_println(rp, 1); fflush(stdout); );
850 savedmcode -= REPLACEMENT_PATCH_SIZE;
852 #if defined(ENABLE_JIT)
853 # if defined(ENABLE_DISASSEMBLER)
854 DOLOG( printf("\tinstruction before: ");
855 disassinstr(rp->pc); fflush(stdout); );
858 md_patch_replacement_point(rp->pc, savedmcode, false);
860 # if defined(ENABLE_DISASSEMBLER)
861 DOLOG( printf("\tinstruction after : ");
862 disassinstr(rp->pc); fflush(stdout); );
866 rp->flags |= RPLPOINT_FLAG_ACTIVE;
869 assert(savedmcode == code->savedmcode);
873 /* replace_deactivate_replacement_points ***************************************
875 Deactivate a replacement points in the given compilation unit.
876 When this function returns, the replacement points will be "un-armed",
877 that is a each thread reaching a point will just continue normally.
880 code.............the compilation unit
882 *******************************************************************************/
884 void replace_deactivate_replacement_points(codeinfo *code)
891 if (code->savedmcode == NULL) {
892 /* disarm countdown points by patching the branches */
894 i = code->rplpointcount;
895 rp = code->rplpoints;
897 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
898 == RPLPOINT_FLAG_COUNTDOWN)
901 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
908 assert(code->savedmcode != NULL);
909 savedmcode = code->savedmcode;
911 /* de-activate each trappable replacement point */
913 i = code->rplpointcount;
914 rp = code->rplpoints;
917 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
922 DOLOG( printf("deactivate replacement point:\n");
923 replace_replacement_point_println(rp, 1); fflush(stdout); );
925 #if defined(ENABLE_JIT)
926 # if defined(ENABLE_DISASSEMBLER)
927 DOLOG( printf("\tinstruction before: ");
928 disassinstr(rp->pc); fflush(stdout); );
931 md_patch_replacement_point(rp->pc, savedmcode, true);
933 # if defined(ENABLE_DISASSEMBLER)
934 DOLOG( printf("\tinstruction before: ");
935 disassinstr(rp->pc); fflush(stdout); );
939 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
941 savedmcode += REPLACEMENT_PATCH_SIZE;
944 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
946 /* free saved machine code */
948 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
949 code->savedmcode = NULL;
953 /******************************************************************************/
954 /* PART III: The replacement mechanism */
955 /******************************************************************************/
958 /* replace_read_value **********************************************************
960 Read a value with the given allocation from the execution state.
963 es...............execution state
964 ra...............allocation
965 javaval..........where to put the value
968 *javaval.........the value
970 *******************************************************************************/
972 static void replace_read_value(executionstate_t *es,
974 replace_val_t *javaval)
976 if (ra->flags & INMEMORY) {
977 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
978 #ifdef HAS_4BYTE_STACKSLOT
979 if (IS_2_WORD_TYPE(ra->type)) {
980 javaval->l = *(u8*)(es->sp + ra->regoff);
984 javaval->p = *(ptrint*)(es->sp + ra->regoff);
985 #ifdef HAS_4BYTE_STACKSLOT
990 /* allocated register */
991 if (IS_FLT_DBL_TYPE(ra->type)) {
992 javaval->d = es->fltregs[ra->regoff];
994 if (ra->type == TYPE_FLT)
995 javaval->f = javaval->d;
997 #if defined(HAS_ADDRESS_REGISTER_FILE)
998 else if (IS_ADR_TYPE(ra->type)) {
999 javaval->p = es->adrregs[ra->regoff];
1003 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1004 if (ra->type == TYPE_LNG) {
1005 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
1006 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
1009 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
1010 javaval->p = es->intregs[ra->regoff];
1016 /* replace_write_value *********************************************************
1018 Write a value to the given allocation in the execution state.
1021 es...............execution state
1022 ra...............allocation
1023 *javaval.........the value
1025 *******************************************************************************/
1027 static void replace_write_value(executionstate_t *es,
1029 replace_val_t *javaval)
1031 if (ra->flags & INMEMORY) {
1032 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1033 #ifdef HAS_4BYTE_STACKSLOT
1034 if (IS_2_WORD_TYPE(ra->type)) {
1035 *(u8*)(es->sp + ra->regoff) = javaval->l;
1039 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1040 #ifdef HAS_4BYTE_STACKSLOT
1045 /* allocated register */
1048 es->fltregs[ra->regoff] = (double) javaval->f;
1051 es->fltregs[ra->regoff] = javaval->d;
1053 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1055 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1056 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1059 #if defined(HAS_ADDRESS_REGISTER_FILE)
1061 es->adrregs[ra->regoff] = javaval->p;
1064 es->intregs[ra->regoff] = javaval->p;
1070 /* replace_new_sourceframe *****************************************************
1072 Allocate a new source frame and insert it at the front of the frame list.
1075 ss...............the source state
1078 ss->frames.......set to new frame (the new head of the frame list).
1081 returns the new frame
1083 *******************************************************************************/
1085 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1087 sourceframe_t *frame;
1089 frame = DNEW(sourceframe_t);
1090 MZERO(frame, sourceframe_t, 1);
1092 frame->down = ss->frames;
1099 /* replace_read_executionstate *************************************************
1101 Read a source frame from the given executions state.
1102 The new source frame is pushed to the front of the frame list of the
1106 rp...............replacement point at which `es` was taken
1107 es...............execution state
1108 ss...............the source state to add the source frame to
1109 topframe.........true, if the first (top-most) source frame on the
1113 *ss..............the source state with the newly created source frame
1116 *******************************************************************************/
1118 static s4 replace_normalize_type_map[] = {
1119 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1120 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1121 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1122 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1123 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1124 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1125 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1129 static void replace_read_executionstate(rplpoint *rp,
1130 executionstate_t *es,
1139 sourceframe_t *frame;
1142 stackslot_t *basesp;
1144 code = code_find_codeinfo_for_pc(rp->pc);
1146 topslot = TOP_IS_NORMAL;
1150 sp = (stackslot_t *) es->sp;
1152 /* in some cases the top stack slot is passed in REG_ITMP1 */
1154 if (rp->type == BBTYPE_EXH) {
1155 topslot = TOP_IS_IN_ITMP1;
1158 /* calculate base stack pointer */
1160 basesp = sp + code->stackframesize;
1162 /* create the source frame */
1164 frame = replace_new_sourceframe(ss);
1165 frame->method = rp->method;
1167 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1168 frame->type = replace_normalize_type_map[rp->type];
1170 frame->fromcode = code;
1172 /* read local variables */
1174 count = m->maxlocals;
1175 frame->javalocalcount = count;
1176 frame->javalocals = DMNEW(replace_val_t, count);
1177 frame->javalocaltype = DMNEW(u1, count);
1179 /* mark values as undefined */
1180 for (i=0; i<count; ++i) {
1181 #if !defined(NDEBUG)
1182 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1184 frame->javalocaltype[i] = TYPE_VOID;
1187 /* some entries in the intregs array are not meaningful */
1188 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1189 #if !defined(NDEBUG)
1190 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1192 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1194 #endif /* !defined(NDEBUG) */
1196 /* read javalocals */
1198 count = rp->regalloccount;
1201 while (count && (i = ra->index) >= 0) {
1202 assert(i < m->maxlocals);
1203 frame->javalocaltype[i] = ra->type;
1204 if (ra->type == TYPE_RET)
1205 frame->javalocals[i].i = ra->regoff;
1207 replace_read_value(es, ra, frame->javalocals + i);
1212 /* read instance, if this is the first rplpoint */
1214 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1215 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1217 /* we are at the start of the method body, so if local 0 is set, */
1218 /* it is the instance. */
1219 if (frame->javalocaltype[0] == TYPE_ADR)
1220 frame->instance = frame->javalocals[0];
1225 md = rp->method->parseddesc;
1227 assert(md->paramcount >= 1);
1228 instra.type = TYPE_ADR;
1229 instra.regoff = md->params[0].regoff;
1230 if (md->params[0].inmemory) {
1231 instra.flags = INMEMORY;
1232 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1237 replace_read_value(es, &instra, &(frame->instance));
1240 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1242 /* read stack slots */
1244 frame->javastackdepth = count;
1245 frame->javastack = DMNEW(replace_val_t, count);
1246 frame->javastacktype = DMNEW(u1, count);
1248 #if !defined(NDEBUG)
1249 /* mark values as undefined */
1250 for (i=0; i<count; ++i) {
1251 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1252 frame->javastacktype[i] = TYPE_VOID;
1254 #endif /* !defined(NDEBUG) */
1258 /* the first stack slot is special in SBR and EXH blocks */
1260 if (topslot == TOP_IS_ON_STACK) {
1263 assert(ra->index == RPLALLOC_STACK);
1264 assert(ra->type == TYPE_ADR);
1265 frame->javastack[i].p = sp[-1];
1266 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1271 else if (topslot == TOP_IS_IN_ITMP1) {
1274 assert(ra->index == RPLALLOC_STACK);
1275 assert(ra->type == TYPE_ADR);
1276 frame->javastack[i].p = es->intregs[REG_ITMP1];
1277 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1282 else if (topslot == TOP_IS_VOID) {
1285 assert(ra->index == RPLALLOC_STACK);
1286 frame->javastack[i].l = 0;
1287 frame->javastacktype[i] = TYPE_VOID;
1293 /* read remaining stack slots */
1295 for (; count--; ra++) {
1296 if (ra->index == RPLALLOC_SYNC) {
1297 assert(rp->type == RPLPOINT_TYPE_INLINE);
1299 /* only read synchronization slots when traversing an inline point */
1302 sourceframe_t *calleeframe = frame->down;
1303 assert(calleeframe);
1304 assert(calleeframe->syncslotcount == 0);
1305 assert(calleeframe->syncslots == NULL);
1307 calleeframe->syncslotcount = 1;
1308 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1309 replace_read_value(es,ra,calleeframe->syncslots);
1312 frame->javastackdepth--;
1316 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1318 /* do not read parameters of calls down the call chain */
1320 if (!topframe && ra->index == RPLALLOC_PARAM) {
1321 frame->javastackdepth--;
1324 if (ra->type == TYPE_RET)
1325 frame->javastack[i].i = ra->regoff;
1327 replace_read_value(es,ra,frame->javastack + i);
1328 frame->javastacktype[i] = ra->type;
1335 /* replace_write_executionstate ************************************************
1337 Pop a source frame from the front of the frame list of the given source state
1338 and write its values into the execution state.
1341 rp...............replacement point for which execution state should be
1343 es...............the execution state to modify
1344 ss...............the given source state
1345 topframe.........true, if this is the last (top-most) source frame to be
1349 *es..............the execution state derived from the source state
1351 *******************************************************************************/
1353 static void replace_write_executionstate(rplpoint *rp,
1354 executionstate_t *es,
1363 sourceframe_t *frame;
1366 stackslot_t *basesp;
1368 code = code_find_codeinfo_for_pc(rp->pc);
1370 topslot = TOP_IS_NORMAL;
1372 /* pop a source frame */
1376 ss->frames = frame->down;
1378 /* calculate stack pointer */
1380 sp = (stackslot_t *) es->sp;
1382 basesp = sp + code->stackframesize;
1384 /* in some cases the top stack slot is passed in REG_ITMP1 */
1386 if (rp->type == BBTYPE_EXH) {
1387 topslot = TOP_IS_IN_ITMP1;
1390 /* write javalocals */
1393 count = rp->regalloccount;
1395 while (count && (i = ra->index) >= 0) {
1396 assert(i < m->maxlocals);
1397 assert(i < frame->javalocalcount);
1398 assert(ra->type == frame->javalocaltype[i]);
1399 if (ra->type == TYPE_RET) {
1400 /* XXX assert that it matches this rplpoint */
1403 replace_write_value(es, ra, frame->javalocals + i);
1408 /* write stack slots */
1412 /* the first stack slot is special in SBR and EXH blocks */
1414 if (topslot == TOP_IS_ON_STACK) {
1417 assert(ra->index == RPLALLOC_STACK);
1418 assert(i < frame->javastackdepth);
1419 assert(frame->javastacktype[i] == TYPE_ADR);
1420 sp[-1] = frame->javastack[i].p;
1425 else if (topslot == TOP_IS_IN_ITMP1) {
1428 assert(ra->index == RPLALLOC_STACK);
1429 assert(i < frame->javastackdepth);
1430 assert(frame->javastacktype[i] == TYPE_ADR);
1431 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1436 else if (topslot == TOP_IS_VOID) {
1439 assert(ra->index == RPLALLOC_STACK);
1440 assert(i < frame->javastackdepth);
1441 assert(frame->javastacktype[i] == TYPE_VOID);
1447 /* write remaining stack slots */
1449 for (; count--; ra++) {
1450 if (ra->index == RPLALLOC_SYNC) {
1451 assert(rp->type == RPLPOINT_TYPE_INLINE);
1453 /* only write synchronization slots when traversing an inline point */
1456 assert(frame->down);
1457 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1458 assert(frame->down->syncslots != NULL);
1460 replace_write_value(es,ra,frame->down->syncslots);
1465 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1467 /* do not write parameters of calls down the call chain */
1469 if (!topframe && ra->index == RPLALLOC_PARAM) {
1473 assert(i < frame->javastackdepth);
1474 assert(ra->type == frame->javastacktype[i]);
1475 if (ra->type == TYPE_RET) {
1476 /* XXX assert that it matches this rplpoint */
1479 replace_write_value(es,ra,frame->javastack + i);
1491 /* replace_pop_activation_record ***********************************************
1493 Peel a stack frame from the execution state.
1495 *** This function imitates the effects of the method epilog ***
1496 *** and returning from the method call. ***
1499 es...............execution state
1500 frame............source frame, receives synchronization slots
1503 *es..............the execution state after popping the stack frame
1505 *******************************************************************************/
1507 u1* replace_pop_activation_record(executionstate_t *es,
1508 sourceframe_t *frame)
1516 stackslot_t *basesp;
1522 /* read the return address */
1524 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1525 if (code_is_leafmethod(es->code))
1526 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1529 ra = md_stacktrace_get_returnaddress(es->sp,
1530 SIZE_OF_STACKSLOT * es->code->stackframesize);
1532 DOLOG( printf("RA = %p\n", (void*)ra); );
1536 /* calculate the base of the stack frame */
1538 sp = (stackslot_t *) es->sp;
1539 basesp = sp + es->code->stackframesize;
1541 /* read slots used for synchronization */
1543 assert(frame->syncslotcount == 0);
1544 assert(frame->syncslots == NULL);
1545 count = code_get_sync_slot_count(es->code);
1546 frame->syncslotcount = count;
1547 frame->syncslots = DMNEW(replace_val_t, count);
1548 for (i=0; i<count; ++i) {
1549 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1552 /* restore return address, if part of frame */
1554 #if defined(REPLACE_RA_TOP_OF_FRAME)
1555 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1556 if (!code_is_leafmethod(es->code))
1558 es->intregs[REPLACE_REG_RA] = *--basesp;
1559 #endif /* REPLACE_RA_TOP_OF_FRAME */
1561 #if defined(REPLACE_RA_LINKAGE_AREA)
1562 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1563 if (!code_is_leafmethod(es->code))
1565 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1566 #endif /* REPLACE_RA_LINKAGE_AREA */
1568 /* restore saved int registers */
1571 for (i=0; i<es->code->savedintcount; ++i) {
1572 while (nregdescint[--reg] != REG_SAV)
1574 es->intregs[reg] = *--basesp;
1577 /* restore saved flt registers */
1581 for (i=0; i<es->code->savedfltcount; ++i) {
1582 while (nregdescfloat[--reg] != REG_SAV)
1584 basesp -= STACK_SLOTS_PER_FLOAT;
1585 es->fltregs[reg] = *(double*)basesp;
1588 #if defined(HAS_ADDRESS_REGISTER_FILE)
1589 /* restore saved adr registers */
1592 for (i=0; i<es->code->savedadrcount; ++i) {
1593 while (nregdescadr[--reg] != REG_SAV)
1595 es->adrregs[reg] = *--basesp;
1599 /* adjust the stackpointer */
1601 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1603 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1604 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1607 /* Set the new pc. Subtract one so we do not hit the replacement point */
1608 /* of the instruction following the call, if there is one. */
1612 /* find the new codeinfo */
1614 pv = md_codegen_get_pv_from_pc(ra);
1615 DOLOG( printf("PV = %p\n", (void*) pv); );
1617 code = code_get_codeinfo_for_pv(pv);
1618 DOLOG( printf("CODE = %p\n", (void*) code); );
1620 /* return NULL if we reached native code */
1625 /* in debugging mode clobber non-saved registers */
1627 #if !defined(NDEBUG)
1629 for (i=0; i<INT_REG_CNT; ++i)
1630 if ((nregdescint[i] != REG_SAV)
1632 && (i != REPLACE_REG_RA)
1635 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1636 for (i=0; i<FLT_REG_CNT; ++i)
1637 if (nregdescfloat[i] != REG_SAV)
1638 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1639 # if defined(HAS_ADDRESS_REGISTER_FILE)
1640 for (i=0; i<ADR_REG_CNT; ++i)
1641 if (nregdescadr[i] != REG_SAV)
1642 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1644 #endif /* !defined(NDEBUG) */
1646 return (code) ? ra : NULL;
1650 /* replace_patch_method_pointer ************************************************
1652 Patch a method pointer (may be in code, data segment, vftbl, or interface
1656 mpp..............address of the method pointer to patch
1657 entrypoint.......the new entrypoint of the method
1658 kind.............kind of call to patch, used only for debugging
1660 *******************************************************************************/
1662 static void replace_patch_method_pointer(methodptr *mpp,
1663 methodptr entrypoint,
1666 #if !defined(NDEBUG)
1671 DOLOG( printf("patch method pointer from: %p to %p\n",
1672 (void*) *mpp, (void*)entrypoint); );
1674 #if !defined(NDEBUG)
1675 oldcode = code_get_codeinfo_for_pv(*mpp);
1676 newcode = code_get_codeinfo_for_pv(entrypoint);
1678 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1679 method_println(oldcode->m);
1680 printf("\t with %p ", (void*) newcode);
1681 method_println(newcode->m); );
1683 assert(oldcode->m == newcode->m);
1686 /* write the new entrypoint */
1688 *mpp = (methodptr) entrypoint;
1692 /* replace_patch_class *********************************************************
1694 Patch a method in the given class.
1697 vftbl............vftbl of the class
1698 m................the method to patch
1699 oldentrypoint....the old entrypoint to replace
1700 entrypoint.......the new entrypoint
1702 *******************************************************************************/
1704 void replace_patch_class(vftbl_t *vftbl,
1713 /* patch the vftbl of the class */
1715 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1719 /* patch the interface tables */
1721 assert(oldentrypoint);
1723 for (i=0; i < vftbl->interfacetablelength; ++i) {
1724 mpp = vftbl->interfacetable[-i];
1725 mppend = mpp + vftbl->interfacevftbllength[i];
1726 for (; mpp != mppend; ++mpp)
1727 if (*mpp == oldentrypoint) {
1728 replace_patch_method_pointer(mpp, entrypoint, "interface");
1734 /* replace_patch_class_hierarchy ***********************************************
1736 Patch a method in all loaded classes.
1739 m................the method to patch
1740 oldentrypoint....the old entrypoint to replace
1741 entrypoint.......the new entrypoint
1743 *******************************************************************************/
1745 struct replace_patch_data_t {
1751 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1753 vftbl_t *vftbl = c->vftbl;
1756 && vftbl->vftbllength > pd->m->vftblindex
1757 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1758 && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
1760 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1764 void replace_patch_class_hierarchy(methodinfo *m,
1768 struct replace_patch_data_t pd;
1771 pd.oldentrypoint = oldentrypoint;
1772 pd.entrypoint = entrypoint;
1774 DOLOG_SHORT( printf("patching class hierarchy: ");
1775 method_println(m); );
1777 classcache_foreach_loaded_class(
1778 (classcache_foreach_functionptr_t) &replace_patch_callback,
1783 /* replace_patch_future_calls **************************************************
1785 Analyse a call site and depending on the kind of call patch the call, the
1786 virtual function table, or the interface table.
1789 ra...............return address pointing after the call site
1790 callerframe......source frame of the caller
1791 calleeframe......source frame of the callee, must have been mapped
1793 *******************************************************************************/
1795 void replace_patch_future_calls(u1 *ra,
1796 sourceframe_t *callerframe,
1797 sourceframe_t *calleeframe)
1800 methodptr entrypoint;
1801 methodptr oldentrypoint;
1804 codeinfo *calleecode;
1805 methodinfo *calleem;
1810 assert(callerframe->down == calleeframe);
1812 /* get the new codeinfo and the method that shall be entered */
1814 calleecode = calleeframe->tocode;
1817 calleem = calleeframe->method;
1818 assert(calleem == calleecode->m);
1820 entrypoint = (methodptr) calleecode->entrypoint;
1822 /* check if we are at an method entry rplpoint at the innermost frame */
1824 atentry = (calleeframe->down == NULL)
1825 && !(calleem->flags & ACC_STATIC)
1826 && (calleeframe->fromrp->id == 0); /* XXX */
1828 /* get the position to patch, in case it was a statically bound call */
1830 pv = callerframe->fromcode->entrypoint;
1831 patchpos = md_jit_method_patch_address(pv, ra, NULL);
1833 if (patchpos == NULL) {
1834 /* the call was dispatched dynamically */
1836 /* we can only patch such calls if we are at the entry point */
1841 assert((calleem->flags & ACC_STATIC) == 0);
1843 oldentrypoint = calleeframe->fromcode->entrypoint;
1845 /* we need to know the instance */
1847 if (!calleeframe->instance.a) {
1848 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1849 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1855 obj = calleeframe->instance.a;
1858 assert(vftbl->class->vftbl == vftbl);
1860 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1862 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1865 /* the call was statically bound */
1867 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1872 /* replace_push_activation_record **********************************************
1874 Push a stack frame onto the execution state.
1876 *** This function imitates the effects of a call and the ***
1877 *** method prolog of the callee. ***
1880 es...............execution state
1881 rpcall...........the replacement point at the call site
1882 callerframe......source frame of the caller, or NULL for creating the
1884 calleeframe......source frame of the callee, must have been mapped
1887 *es..............the execution state after pushing the stack frame
1889 *******************************************************************************/
1891 void replace_push_activation_record(executionstate_t *es,
1893 sourceframe_t *callerframe,
1894 sourceframe_t *calleeframe)
1899 stackslot_t *basesp;
1902 codeinfo *calleecode;
1905 assert(!rpcall || callerframe);
1906 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1907 assert(!rpcall || rpcall == callerframe->torp);
1908 assert(calleeframe);
1909 assert(!callerframe || calleeframe == callerframe->down);
1911 /* the compilation unit we are entering */
1913 calleecode = calleeframe->tocode;
1916 /* calculate the return address */
1919 ra = rpcall->pc + rpcall->callsize;
1921 ra = es->pc + 1 /* XXX this is ugly */;
1923 /* write the return address */
1925 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1926 es->sp -= SIZE_OF_STACKSLOT;
1928 *((stackslot_t *)es->sp) = (stackslot_t) ra;
1929 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1931 #if defined(REPLACE_REG_RA)
1932 es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1935 /* we move into a new code unit */
1937 es->code = calleecode;
1939 /* set the new pc XXX not needed? */
1941 es->pc = calleecode->entrypoint;
1943 /* build the stackframe */
1945 DOLOG( printf("building stackframe of %d words at %p\n",
1946 calleecode->stackframesize, (void*)es->sp); );
1948 sp = (stackslot_t *) es->sp;
1951 sp -= calleecode->stackframesize;
1954 /* in debug mode, invalidate stack frame first */
1956 /* XXX may not invalidate linkage area used by native code! */
1957 #if !defined(NDEBUG) && 0
1958 for (i=0; i<(basesp - sp); ++i) {
1959 sp[i] = 0xdeaddeadU;
1963 /* save the return address register */
1965 #if defined(REPLACE_RA_TOP_OF_FRAME)
1966 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1967 if (!code_is_leafmethod(calleecode))
1969 *--basesp = (ptrint) ra;
1970 #endif /* REPLACE_RA_TOP_OF_FRAME */
1972 #if defined(REPLACE_RA_LINKAGE_AREA)
1973 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1974 if (!code_is_leafmethod(calleecode))
1976 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1977 #endif /* REPLACE_RA_LINKAGE_AREA */
1979 /* save int registers */
1982 for (i=0; i<calleecode->savedintcount; ++i) {
1983 while (nregdescint[--reg] != REG_SAV)
1985 *--basesp = es->intregs[reg];
1987 /* XXX may not clobber saved regs used by native code! */
1988 #if !defined(NDEBUG) && 0
1989 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1993 /* save flt registers */
1997 for (i=0; i<calleecode->savedfltcount; ++i) {
1998 while (nregdescfloat[--reg] != REG_SAV)
2000 basesp -= STACK_SLOTS_PER_FLOAT;
2001 *(double*)basesp = es->fltregs[reg];
2003 /* XXX may not clobber saved regs used by native code! */
2004 #if !defined(NDEBUG) && 0
2005 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
2009 #if defined(HAS_ADDRESS_REGISTER_FILE)
2010 /* save adr registers */
2013 for (i=0; i<calleecode->savedadrcount; ++i) {
2014 while (nregdescadr[--reg] != REG_SAV)
2016 *--basesp = es->adrregs[reg];
2018 /* XXX may not clobber saved regs used by native code! */
2019 #if !defined(NDEBUG) && 0
2020 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
2025 /* write slots used for synchronization */
2027 count = code_get_sync_slot_count(calleecode);
2028 assert(count == calleeframe->syncslotcount);
2029 for (i=0; i<count; ++i) {
2030 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2035 es->pv = calleecode->entrypoint;
2037 /* redirect future invocations */
2039 if (callerframe && rpcall) {
2040 #if defined(REPLACE_PATCH_ALL)
2041 if (rpcall->type == callerframe->fromrp->type)
2043 if (rpcall == callerframe->fromrp)
2045 replace_patch_future_calls(ra, callerframe, calleeframe);
2050 /* replace_find_replacement_point **********************************************
2052 Find the replacement point in the given code corresponding to the
2053 position given in the source frame.
2056 code.............the codeinfo in which to search the rplpoint
2057 frame............the source frame defining the position to look for
2058 parent...........parent replacement point to match
2061 the replacement point
2063 *******************************************************************************/
2065 rplpoint * replace_find_replacement_point(codeinfo *code,
2066 sourceframe_t *frame,
2079 DOLOG( printf("searching replacement point for:\n");
2080 replace_source_frame_println(frame); );
2084 DOLOG( printf("code = %p\n", (void*)code); );
2086 rp = code->rplpoints;
2087 i = code->rplpointcount;
2089 if (rp->id == frame->id && rp->method == frame->method
2090 && rp->parent == parent
2091 && replace_normalize_type_map[rp->type] == frame->type)
2093 /* check if returnAddresses match */
2094 /* XXX optimize: only do this if JSRs in method */
2095 DOLOG( printf("checking match for:");
2096 replace_replacement_point_println(rp, 1); fflush(stdout); );
2099 for (j = rp->regalloccount; j--; ++ra) {
2100 if (ra->type == TYPE_RET) {
2101 if (ra->index == RPLALLOC_STACK) {
2102 assert(stacki < frame->javastackdepth);
2103 if (frame->javastack[stacki].i != ra->regoff)
2108 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2109 if (frame->javalocals[ra->index].i != ra->regoff)
2122 #if !defined(NDEBUG)
2123 printf("candidate replacement points were:\n");
2124 rp = code->rplpoints;
2125 i = code->rplpointcount;
2127 replace_replacement_point_println(rp, 1);
2131 vm_abort("no matching replacement point found");
2132 return NULL; /* NOT REACHED */
2136 /* replace_find_replacement_point_for_pc ***************************************
2138 Find the nearest replacement point at or before the given PC. The
2139 given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
2140 the replacement point to be found.
2143 code.............compilation unit the PC is in
2144 pc...............the machine code PC
2147 the replacement point found, or
2148 NULL if no replacement point was found
2150 *******************************************************************************/
2152 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2158 DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
2159 method_println(code->m); );
2163 rp = code->rplpoints;
2164 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2165 DOLOG( replace_replacement_point_println(rp, 2); );
2166 if (rp->pc <= pc && rp->pc + rp->callsize >= pc)
2174 /* replace_pop_native_frame ****************************************************
2176 Unroll a native frame in the execution state and create a source frame
2180 es...............current execution state
2181 ss...............the current source state
2182 sfi..............stackframeinfo for the native frame
2185 es...............execution state after unrolling the native frame
2186 ss...............gets the added native source frame
2188 *******************************************************************************/
2190 static void replace_pop_native_frame(executionstate_t *es,
2192 stackframeinfo *sfi)
2194 sourceframe_t *frame;
2200 frame = replace_new_sourceframe(ss);
2204 /* remember pc and size of native frame */
2206 frame->nativepc = es->pc;
2207 frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2208 assert(frame->nativeframesize >= 0);
2210 /* remember values of saved registers */
2213 for (i=0; i<INT_REG_CNT; ++i) {
2214 if (nregdescint[i] == REG_SAV)
2215 frame->nativesavint[j++] = es->intregs[i];
2219 for (i=0; i<FLT_REG_CNT; ++i) {
2220 if (nregdescfloat[i] == REG_SAV)
2221 frame->nativesavflt[j++] = es->fltregs[i];
2224 #if defined(HAS_ADDRESS_REGISTER_FILE)
2226 for (i=0; i<ADR_REG_CNT; ++i) {
2227 if (nregdescadr[i] == REG_SAV)
2228 frame->nativesavadr[j++] = es->adrregs[i];
2232 /* restore saved registers */
2234 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2236 for (i=0; i<INT_REG_CNT; ++i) {
2237 if (nregdescint[i] == REG_SAV)
2238 es->intregs[i] = sfi->intregs[j++];
2241 /* XXX we don't have them, yet, in the sfi, so clear them */
2243 for (i=0; i<INT_REG_CNT; ++i) {
2244 if (nregdescint[i] == REG_SAV)
2249 /* XXX we don't have float registers in the sfi, so clear them */
2251 for (i=0; i<FLT_REG_CNT; ++i) {
2252 if (nregdescfloat[i] == REG_SAV)
2253 es->fltregs[i] = 0.0;
2256 #if defined(HAS_ADDRESS_REGISTER_FILE)
2257 # if defined(ENABLE_GC_CACAO)
2259 for (i=0; i<ADR_REG_CNT; ++i) {
2260 if (nregdescadr[i] == REG_SAV)
2261 es->adrregs[i] = sfi->adrregs[j++];
2264 for (i=0; i<ADR_REG_CNT; ++i) {
2265 if (nregdescadr[i] == REG_SAV)
2271 /* restore codeinfo of the native stub */
2273 code = code_get_codeinfo_for_pv(sfi->pv);
2275 /* restore sp, pv, pc and codeinfo of the parent method */
2277 /* XXX michi: use this instead:
2278 es->sp = sfi->sp + code->stackframesize; */
2279 es->sp = sfi->sp + (*(s4 *) (sfi->pv + FrameSize));
2280 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2281 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
2283 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2284 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2285 es->code = code_get_codeinfo_for_pv(es->pv);
2289 /* replace_push_native_frame ***************************************************
2291 Rebuild a native frame onto the execution state and remove its source frame.
2293 Note: The native frame is "rebuild" by setting fields like PC and stack
2294 pointer in the execution state accordingly. Values in the
2295 stackframeinfo may be modified, but the actual stack frame of the
2296 native code is not touched.
2299 es...............current execution state
2300 ss...............the current source state
2303 es...............execution state after re-rolling the native frame
2304 ss...............the native source frame is removed
2306 *******************************************************************************/
2308 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2310 sourceframe_t *frame;
2316 DOLOG( printf("pushing native frame\n"); );
2318 /* remove the frame from the source state */
2322 assert(REPLACE_IS_NATIVE_FRAME(frame));
2324 ss->frames = frame->down;
2326 /* skip sp for the native stub */
2328 es->sp -= (*(s4 *) (frame->sfi->pv + FrameSize));
2329 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2330 es->sp -= SIZE_OF_STACKSLOT; /* skip return address */
2333 /* assert that the native frame has not moved */
2335 assert(es->sp == frame->sfi->sp);
2337 /* update saved registers in the stackframeinfo */
2339 #if defined(ENABLE_GC_CACAO)
2341 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2342 for (i=0; i<INT_REG_CNT; ++i) {
2343 if (nregdescint[i] == REG_SAV)
2344 frame->sfi->intregs[j++] = es->intregs[i];
2347 for (i=0; i<ADR_REG_CNT; ++i) {
2348 if (nregdescadr[i] == REG_SAV)
2349 frame->sfi->adrregs[j++] = es->adrregs[i];
2353 /* XXX leave float registers untouched here */
2356 /* restore saved registers */
2359 for (i=0; i<INT_REG_CNT; ++i) {
2360 if (nregdescint[i] == REG_SAV)
2361 es->intregs[i] = frame->nativesavint[j++];
2365 for (i=0; i<FLT_REG_CNT; ++i) {
2366 if (nregdescfloat[i] == REG_SAV)
2367 es->fltregs[i] = frame->nativesavflt[j++];
2370 #if defined(HAS_ADDRESS_REGISTER_FILE)
2372 for (i=0; i<ADR_REG_CNT; ++i) {
2373 if (nregdescadr[i] == REG_SAV)
2374 es->adrregs[i] = frame->nativesavadr[j++];
2378 /* skip the native frame on the machine stack */
2380 es->sp -= frame->nativeframesize;
2382 /* set the pc the next frame must return to */
2384 es->pc = frame->nativepc;
2388 /* replace_recover_source_state ************************************************
2390 Recover the source state from the given replacement point and execution
2394 rp...............replacement point that has been reached, if any
2395 sfi..............stackframeinfo, if called from native code
2396 es...............execution state at the replacement point rp
2401 *******************************************************************************/
2403 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2404 stackframeinfo *sfi,
2405 executionstate_t *es)
2410 #if defined(REPLACE_STATISTICS)
2414 /* create the source frame structure in dump memory */
2416 ss = DNEW(sourcestate_t);
2419 /* each iteration of the loop recovers one source frame */
2426 DOLOG( replace_executionstate_println(es); );
2428 /* if we are not at a replacement point, it is a native frame */
2431 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2434 replace_pop_native_frame(es, ss, sfi);
2437 if (es->code == NULL)
2440 goto after_machine_frame;
2443 /* read the values for this source frame from the execution state */
2445 DOLOG( printf("recovering source state for%s:\n",
2446 (ss->frames == NULL) ? " TOPFRAME" : "");
2447 replace_replacement_point_println(rp, 1); );
2449 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2451 #if defined(ENABLE_VMLOG)
2452 vmlog_cacao_unrol_method(ss->frames->method);
2455 #if defined(REPLACE_STATISTICS)
2456 REPLACE_COUNT(stat_frames);
2458 replace_statistics_source_frame(ss->frames);
2461 /* in locked areas (below native frames), identity map the frame */
2464 ss->frames->torp = ss->frames->fromrp;
2465 ss->frames->tocode = ss->frames->fromcode;
2468 /* unroll to the next (outer) frame */
2471 /* this frame is in inlined code */
2473 DOLOG( printf("INLINED!\n"); );
2477 assert(rp->type == RPLPOINT_TYPE_INLINE);
2478 REPLACE_COUNT(stat_unroll_inline);
2481 /* this frame had been called at machine-level. pop it. */
2483 DOLOG( printf("UNWIND\n"); );
2485 ra = replace_pop_activation_record(es, ss->frames);
2487 DOLOG( printf("REACHED NATIVE CODE\n"); );
2491 #if !defined(ENABLE_GC_CACAO)
2492 break; /* XXX remove to activate native frames */
2497 /* find the replacement point at the call site */
2499 after_machine_frame:
2500 rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2503 vm_abort("could not find replacement point while unrolling call");
2505 DOLOG( printf("found replacement point.\n");
2506 replace_replacement_point_println(rp, 1); );
2508 assert(rp->type == RPLPOINT_TYPE_CALL);
2509 REPLACE_COUNT(stat_unroll_call);
2511 } /* end loop over source frames */
2513 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2519 /* replace_map_source_state ****************************************************
2521 Map each source frame in the given source state to a target replacement
2522 point and compilation unit. If no valid code is available for a source
2523 frame, it is (re)compiled.
2526 ss...............the source state
2529 ss...............the source state, modified: The `torp` and `tocode`
2530 fields of each source frame are set.
2533 true.............everything went ok
2534 false............an exception has been thrown
2536 *******************************************************************************/
2538 static bool replace_map_source_state(sourcestate_t *ss)
2540 sourceframe_t *frame;
2543 rplpoint *parent; /* parent of inlined rplpoint */
2544 #if defined(REPLACE_STATISTICS)
2551 /* iterate over the source frames from outermost to innermost */
2553 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2555 /* XXX skip native frames */
2557 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2562 /* map frames which are not already mapped */
2564 if (frame->tocode) {
2565 code = frame->tocode;
2570 assert(frame->torp == NULL);
2572 if (parent == NULL) {
2573 /* find code for this frame */
2575 #if defined(REPLACE_STATISTICS)
2576 oldcode = frame->method->code;
2578 /* request optimization of hot methods and their callers */
2580 if (frame->method->hitcountdown < 0
2581 || (frame->down && frame->down->method->hitcountdown < 0))
2582 jit_request_optimization(frame->method);
2584 code = jit_get_current_code(frame->method);
2587 return false; /* exception */
2589 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2594 /* map this frame */
2596 rp = replace_find_replacement_point(code, frame, parent);
2598 frame->tocode = code;
2602 if (rp->type == RPLPOINT_TYPE_CALL) {
2615 /* replace_map_source_state_identity *******************************************
2617 Map each source frame in the given source state to the same replacement
2618 point and compilation unit it was derived from. This is mainly used for
2622 ss...............the source state
2625 ss...............the source state, modified: The `torp` and `tocode`
2626 fields of each source frame are set.
2628 *******************************************************************************/
2630 #if defined(ENABLE_GC_CACAO)
2631 static void replace_map_source_state_identity(sourcestate_t *ss)
2633 sourceframe_t *frame;
2635 /* iterate over the source frames from outermost to innermost */
2637 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2639 /* skip native frames */
2641 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2645 /* map frames using the identity mapping */
2647 if (frame->tocode) {
2648 assert(frame->tocode == frame->fromcode);
2649 assert(frame->torp == frame->fromrp);
2651 assert(frame->tocode == NULL);
2652 assert(frame->torp == NULL);
2653 frame->tocode = frame->fromcode;
2654 frame->torp = frame->fromrp;
2661 /* replace_build_execution_state ***********************************************
2663 Build an execution state for the given (mapped) source state.
2665 !!! CAUTION: This function rewrites the machine stack !!!
2667 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2670 ss...............the source state. Must have been mapped by
2671 replace_map_source_state before.
2672 es...............the base execution state on which to build
2675 *es..............the new execution state
2677 *******************************************************************************/
2679 static void replace_build_execution_state(sourcestate_t *ss,
2680 executionstate_t *es)
2683 sourceframe_t *prevframe;
2690 while (ss->frames) {
2692 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2693 prevframe = ss->frames;
2694 replace_push_native_frame(es, ss);
2700 if (parent == NULL) {
2701 /* create a machine-level stack frame */
2703 DOLOG( printf("pushing activation record for:\n");
2704 if (rp) replace_replacement_point_println(rp, 1);
2705 else printf("\tfirst frame\n"); );
2707 replace_push_activation_record(es, rp, prevframe, ss->frames);
2709 DOLOG( replace_executionstate_println(es); );
2712 rp = ss->frames->torp;
2715 DOLOG( printf("creating execution state for%s:\n",
2716 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2717 replace_replacement_point_println(ss->frames->fromrp, 1);
2718 replace_replacement_point_println(rp, 1); );
2720 es->code = ss->frames->tocode;
2721 prevframe = ss->frames;
2723 #if defined(ENABLE_VMLOG)
2724 vmlog_cacao_rerol_method(ss->frames->method);
2727 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2729 DOLOG( replace_executionstate_println(es); );
2731 if (rp->type == RPLPOINT_TYPE_CALL) {
2742 /* replace_me ******************************************************************
2744 This function is called by the signal handler when a thread reaches
2745 a replacement point. `replace_me` must map the execution state to the
2746 target replacement point and let execution continue there.
2748 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2751 rp...............replacement point that has been reached
2752 es...............execution state read by signal handler
2754 *******************************************************************************/
2756 static void replace_me(rplpoint *rp, executionstate_t *es)
2758 stackframeinfo *sfi;
2760 sourceframe_t *frame;
2764 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2765 threadobject *thread;
2768 origcode = es->code;
2771 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2772 stat_replacements, (void*)THREADOBJECT,
2774 method_println(es->code->m); );
2776 DOLOG( replace_replacement_point_println(rp, 1); );
2778 REPLACE_COUNT(stat_replacements);
2780 /* mark start of dump memory area */
2782 dumpsize = dump_size();
2784 /* get the stackframeinfo for the current thread */
2786 sfi = STACKFRAMEINFO;
2788 /* recover source state */
2790 ss = replace_recover_source_state(rp, sfi, es);
2792 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2793 /* if there is a collection pending, we assume the replacement point should
2794 suspend this thread */
2798 thread = THREADOBJECT;
2800 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2802 /* map the sourcestate using the identity mapping */
2803 replace_map_source_state_identity(ss);
2805 /* since we enter the same method again, we turn off rps now */
2806 /* XXX michi: can we really do this? what if the rp was active before
2807 we activated it for the gc? */
2808 replace_deactivate_replacement_points(origcode);
2810 /* remember executionstate and sourcestate for this thread */
2811 GC_EXECUTIONSTATE = es;
2812 GC_SOURCESTATE = ss;
2814 /* really suspend this thread now (PC = 0) */
2815 threads_suspend_ack(NULL, NULL);
2817 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2820 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2822 /* map the source state */
2824 if (!replace_map_source_state(ss))
2825 vm_abort("exception during method replacement");
2827 DOLOG( replace_sourcestate_println(ss); );
2829 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2831 #if !defined(NDEBUG)
2832 /* avoid infinite loops by self-replacement, only if not in testing mode */
2834 if (!opt_TestReplacement) {
2837 frame = frame->down;
2839 if (frame->torp == origrp) {
2841 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2843 replace_deactivate_replacement_points(origcode);
2848 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2852 /* build the new execution state */
2854 replace_build_execution_state(ss, es);
2856 #if !defined(NDEBUG)
2857 /* continue execution after patched machine code, if testing mode enabled */
2859 if (opt_TestReplacement)
2860 es->pc += REPLACEMENT_PATCH_SIZE;
2863 /* release dump area */
2865 dump_release(dumpsize);
2869 /* replace_me_wrapper **********************************************************
2871 This function is called by the signal handler. It determines if there
2872 is an active replacement point pending at the given PC and returns
2875 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2878 pc...............the program counter that triggered the replacement.
2879 context..........the context (machine state) to which the
2880 replacement should be applied.
2883 context..........the context after replacement finished.
2886 true.............replacement done, everything went ok
2887 false............no replacement done, context unchanged
2889 *******************************************************************************/
2891 bool replace_me_wrapper(u1 *pc, void *context)
2895 executionstate_t es;
2897 /* search the codeinfo for the given PC */
2899 code = code_find_codeinfo_for_pc(pc);
2902 /* search for a replacement point at the given PC */
2904 rp = replace_find_replacement_point_for_pc(code, pc);
2906 /* check if the replacement point belongs to given PC and is active */
2908 if ((rp != NULL) && (rp->pc == pc) && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
2910 /* set codeinfo pointer in execution state */
2914 /* read execution state from current context */
2916 md_replace_executionstate_read(&es, context);
2918 DOLOG( printf("REPLACEMENT READ: ");
2919 replace_executionstate_println(&es); );
2921 /* do the actual replacement */
2923 replace_me(rp, &es);
2925 /* write execution state to current context */
2927 md_replace_executionstate_write(&es, context);
2929 DOLOG( printf("REPLACEMENT WRITE: ");
2930 replace_executionstate_println(&es); );
2932 /* new code is entered after returning */
2934 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2942 /******************************************************************************/
2943 /* NOTE: Stuff specific to the exact GC is below. */
2944 /******************************************************************************/
2946 #if defined(ENABLE_GC_CACAO)
2947 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
2949 stackframeinfo *sfi;
2950 executionstate_t *es;
2953 /* get the stackframeinfo of this thread */
2954 assert(thread == THREADOBJECT);
2955 sfi = STACKFRAMEINFO;
2957 /* create the execution state */
2958 es = DNEW(executionstate_t);
2961 es->pv = 0; /* since we are in a native, PV is invalid! */
2962 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
2964 /* we assume we are in a native (no replacement point)! */
2965 ss = replace_recover_source_state(NULL, sfi, es);
2967 /* map the sourcestate using the identity mapping */
2968 replace_map_source_state_identity(ss);
2970 /* remember executionstate and sourcestate for this thread */
2971 GC_EXECUTIONSTATE = es;
2972 GC_SOURCESTATE = ss;
2976 #if defined(ENABLE_GC_CACAO)
2977 void replace_gc_into_native(threadobject *thread)
2979 executionstate_t *es;
2982 /* get the executionstate and sourcestate for the given thread */
2983 es = GC_EXECUTIONSTATE;
2984 ss = GC_SOURCESTATE;
2986 /* rebuild the stack of the given thread */
2987 replace_build_execution_state(ss, es);
2992 /******************************************************************************/
2993 /* NOTE: No important code below. */
2994 /******************************************************************************/
2997 /* statistics *****************************************************************/
2999 #if defined(REPLACE_STATISTICS)
3000 static void print_freq(FILE *file,int *array,int limit)
3005 for (i=0; i<limit; ++i)
3007 sum += array[limit];
3008 for (i=0; i<limit; ++i) {
3010 fprintf(file," %3d: %8d (cum %3d%%)\n",
3011 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3013 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3015 #endif /* defined(REPLACE_STATISTICS) */
3018 #if defined(REPLACE_STATISTICS)
3020 #define REPLACE_PRINT_DIST(name, array) \
3021 printf(" " name " distribution:\n"); \
3022 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3024 void replace_print_statistics(void)
3026 printf("replacement statistics:\n");
3027 printf(" # of replacements: %d\n", stat_replacements);
3028 printf(" # of frames: %d\n", stat_frames);
3029 printf(" # of recompilations: %d\n", stat_recompile);
3030 printf(" patched static calls:%d\n", stat_staticpatch);
3031 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3032 printf(" unrolled calls: %d\n", stat_unroll_call);
3033 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3034 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3035 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3036 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3037 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3038 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3039 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3040 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3041 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3042 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3044 printf(" # of methods: %d\n", stat_methods);
3045 printf(" # of replacement points: %d\n", stat_rploints);
3046 printf(" # of regallocs: %d\n", stat_regallocs);
3047 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3048 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3049 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3053 #endif /* defined(REPLACE_STATISTICS) */
3056 #if defined(REPLACE_STATISTICS)
3057 static void replace_statistics_source_frame(sourceframe_t *frame)
3066 for (i=0; i<frame->javalocalcount; ++i) {
3067 switch (frame->javalocaltype[i]) {
3068 case TYPE_ADR: adr++; break;
3069 case TYPE_RET: ret++; break;
3070 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3071 case TYPE_VOID: vd++; break;
3076 REPLACE_COUNT_DIST(stat_dist_locals, n);
3077 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3078 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3079 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3080 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3081 adr = ret = prim = n = 0;
3082 for (i=0; i<frame->javastackdepth; ++i) {
3083 switch (frame->javastacktype[i]) {
3084 case TYPE_ADR: adr++; break;
3085 case TYPE_RET: ret++; break;
3086 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3090 REPLACE_COUNT_DIST(stat_dist_stack, n);
3091 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3092 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3093 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3095 #endif /* defined(REPLACE_STATISTICS) */
3098 /* debugging helpers **********************************************************/
3100 /* replace_replacement_point_println *******************************************
3102 Print replacement point info.
3105 rp...............the replacement point to print
3107 *******************************************************************************/
3109 #if !defined(NDEBUG)
3111 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3113 static char *replace_type_str[] = {
3123 void replace_replacement_point_println(rplpoint *rp, int depth)
3129 printf("(rplpoint *)NULL\n");
3133 for (j=0; j<depth; ++j)
3136 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3137 rp->id, (void*)rp,rp->pc,rp->callsize,
3138 replace_type_str[rp->type]);
3139 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3141 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3142 printf(" COUNTDOWN");
3143 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3145 printf(" parent:%p\n", (void*)rp->parent);
3146 for (j=0; j<depth; ++j)
3148 printf("ra:%d = [", rp->regalloccount);
3150 for (j=0; j<rp->regalloccount; ++j) {
3153 index = rp->regalloc[j].index;
3155 case RPLALLOC_STACK: printf("S"); break;
3156 case RPLALLOC_PARAM: printf("P"); break;
3157 case RPLALLOC_SYNC : printf("Y"); break;
3158 default: printf("%d", index);
3160 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3161 if (rp->regalloc[j].type == TYPE_RET) {
3162 printf("ret(L%03d)", rp->regalloc[j].regoff);
3165 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3170 for (j=0; j<depth; ++j)
3173 method_print(rp->method);
3177 #endif /* !defined(NDEBUG) */
3180 /* replace_show_replacement_points *********************************************
3182 Print replacement point info.
3185 code.............codeinfo whose replacement points should be printed.
3187 *******************************************************************************/
3189 #if !defined(NDEBUG)
3190 void replace_show_replacement_points(codeinfo *code)
3198 printf("(codeinfo *)NULL\n");
3202 printf("\treplacement points: %d\n",code->rplpointcount);
3204 printf("\ttotal allocations : %d\n",code->regalloccount);
3205 printf("\tsaved int regs : %d\n",code->savedintcount);
3206 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3207 #if defined(HAS_ADDRESS_REGISTER_FILE)
3208 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3210 printf("\tmemuse : %d\n",code->memuse);
3214 for (i=0; i<code->rplpointcount; ++i) {
3215 rp = code->rplpoints + i;
3218 parent = rp->parent;
3221 parent = parent->parent;
3223 replace_replacement_point_println(rp, depth);
3229 /* replace_executionstate_println **********************************************
3231 Print execution state
3234 es...............the execution state to print
3236 *******************************************************************************/
3238 #if !defined(NDEBUG)
3239 void replace_executionstate_println(executionstate_t *es)
3247 printf("(executionstate_t *)NULL\n");
3251 printf("executionstate_t:\n");
3252 printf("\tpc = %p",(void*)es->pc);
3253 printf(" sp = %p",(void*)es->sp);
3254 printf(" pv = %p\n",(void*)es->pv);
3255 #if defined(ENABLE_DISASSEMBLER)
3256 for (i=0; i<INT_REG_CNT; ++i) {
3261 #if SIZEOF_VOID_P == 8
3262 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3264 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3269 for (i=0; i<FLT_REG_CNT; ++i) {
3274 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3278 # if defined(HAS_ADDRESS_REGISTER_FILE)
3279 for (i=0; i<ADR_REG_CNT; ++i) {
3284 printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
3291 sp = (stackslot_t *) es->sp;
3296 methoddesc *md = es->code->m->parseddesc;
3297 slots = es->code->stackframesize;
3298 extraslots = 1 + md->memuse;
3305 printf("\tstack slots(+%d) at sp:", extraslots);
3306 for (i=0; i<slots+extraslots; ++i) {
3309 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3310 #ifdef HAS_4BYTE_STACKSLOT
3311 printf("%08lx",(unsigned long)*sp++);
3313 printf("%016llx",(unsigned long long)*sp++);
3315 printf("%c", (i >= slots) ? ')' : ' ');
3320 printf("\tcode: %p", (void*)es->code);
3321 if (es->code != NULL) {
3322 printf(" stackframesize=%d ", es->code->stackframesize);
3323 method_print(es->code->m);
3331 #if !defined(NDEBUG)
3332 static void java_value_print(s4 type, replace_val_t value)
3337 printf("%016llx",(unsigned long long) value.l);
3339 if (type < 0 || type > TYPE_RET)
3340 printf(" <INVALID TYPE:%d>", type);
3342 printf(" %s", show_jit_type_names[type]);
3344 if (type == TYPE_ADR && value.a != NULL) {
3347 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3349 if (obj->vftbl->class == class_java_lang_String) {
3351 u = javastring_toutf(obj, false);
3352 utf_display_printable_ascii(u);
3356 else if (type == TYPE_INT) {
3357 printf(" %ld", (long) value.i);
3359 else if (type == TYPE_LNG) {
3360 printf(" %lld", (long long) value.l);
3362 else if (type == TYPE_FLT) {
3363 printf(" %f", value.f);
3365 else if (type == TYPE_DBL) {
3366 printf(" %f", value.d);
3369 #endif /* !defined(NDEBUG) */
3372 #if !defined(NDEBUG)
3373 void replace_source_frame_println(sourceframe_t *frame)
3378 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3379 printf("\tNATIVE\n");
3380 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3381 printf("\tnativepc: %p\n", frame->nativepc);
3382 printf("\tframesize: %d\n", frame->nativeframesize);
3385 for (i=0; i<INT_REG_CNT; ++i) {
3386 if (nregdescint[i] == REG_SAV)
3387 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3391 for (i=0; i<FLT_REG_CNT; ++i) {
3392 if (nregdescfloat[i] == REG_SAV)
3393 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3401 method_println(frame->method);
3402 printf("\tid: %d\n", frame->id);
3403 printf("\ttype: %s\n", replace_type_str[frame->type]);
3406 if (frame->instance.a) {
3407 printf("\tinstance: ");
3408 java_value_print(TYPE_ADR, frame->instance);
3412 if (frame->javalocalcount) {
3413 printf("\tlocals (%d):\n",frame->javalocalcount);
3414 for (i=0; i<frame->javalocalcount; ++i) {
3415 t = frame->javalocaltype[i];
3416 if (t == TYPE_VOID) {
3417 printf("\tlocal[ %2d] = void\n",i);
3420 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3421 java_value_print(t, frame->javalocals[i]);
3428 if (frame->javastackdepth) {
3429 printf("\tstack (depth %d):\n",frame->javastackdepth);
3430 for (i=0; i<frame->javastackdepth; ++i) {
3431 t = frame->javastacktype[i];
3432 if (t == TYPE_VOID) {
3433 printf("\tstack[%2d] = void", i);
3436 printf("\tstack[%2d] = ",i);
3437 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3444 if (frame->syncslotcount) {
3445 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3446 for (i=0; i<frame->syncslotcount; ++i) {
3447 printf("\tslot[%2d] = ",i);
3448 #ifdef HAS_4BYTE_STACKSLOT
3449 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3451 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3457 if (frame->fromcode) {
3458 printf("\tfrom %p ", (void*)frame->fromcode);
3459 method_println(frame->fromcode->m);
3461 if (frame->tocode) {
3462 printf("\tto %p ", (void*)frame->tocode);
3463 method_println(frame->tocode->m);
3466 if (frame->fromrp) {
3467 printf("\tfrom replacement point:\n");
3468 replace_replacement_point_println(frame->fromrp, 2);
3471 printf("\tto replacement point:\n");
3472 replace_replacement_point_println(frame->torp, 2);
3477 #endif /* !defined(NDEBUG) */
3480 /* replace_sourcestate_println *************************************************
3485 ss...............the source state to print
3487 *******************************************************************************/
3489 #if !defined(NDEBUG)
3490 void replace_sourcestate_println(sourcestate_t *ss)
3493 sourceframe_t *frame;
3496 printf("(sourcestate_t *)NULL\n");
3500 printf("sourcestate_t:\n");
3502 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3503 printf(" frame %d:\n", i);
3504 replace_source_frame_println(frame);
3510 /* replace_sourcestate_println_short *******************************************
3512 Print a compact representation of the given source state.
3515 ss...............the source state to print
3517 *******************************************************************************/
3519 #if !defined(NDEBUG)
3520 void replace_sourcestate_println_short(sourcestate_t *ss)
3522 sourceframe_t *frame;
3524 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3527 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3528 printf("NATIVE (pc %p size %d) ",
3529 (void*)frame->nativepc, frame->nativeframesize);
3530 replace_stackframeinfo_println(frame->sfi);
3535 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3538 printf("%s", replace_type_str[frame->fromrp->type]);
3540 if (frame->torp && frame->torp->type != frame->fromrp->type)
3541 printf("->%s", replace_type_str[frame->torp->type]);
3543 if (frame->tocode != frame->fromcode)
3544 printf(" (%p->%p/%d) ",
3545 (void*) frame->fromcode, (void*) frame->tocode,
3548 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3550 method_println(frame->method);
3555 #if !defined(NDEBUG)
3556 static void replace_stackframeinfo_println(stackframeinfo *sfi)
3558 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3559 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3560 (void*)sfi->ra, (void*)sfi->xpc);
3563 method_println(sfi->method);
3570 * These are local overrides for various environment variables in Emacs.
3571 * Please do not remove this and leave it at the end of the file, where
3572 * Emacs will automagically detect them.
3573 * ---------------------------------------------------------------------
3576 * indent-tabs-mode: t
3580 * vim:noexpandtab:sw=4:ts=4: