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
37 #include "mm/memory.h"
39 #include "threads/threads-common.h"
41 #include "toolbox/logging.h"
43 #include "vm/stringlocal.h"
45 #include "vm/jit/abi.h"
46 #include "vm/jit/asmpart.h"
47 #include "vm/jit/disass.h"
48 #include "vm/jit/jit.h"
49 #include "vm/jit/md.h"
50 #include "vm/jit/methodheader.h"
51 #include "vm/jit/replace.h"
52 #include "vm/jit/show.h"
53 #include "vm/jit/stack.h"
55 #include "vmcore/options.h"
56 #include "vmcore/classcache.h"
59 #define REPLACE_PATCH_DYNAMIC_CALL
60 /*#define REPLACE_PATCH_ALL*/
62 #if defined(ENABLE_VMLOG)
63 #include <vmlog_cacao.h>
66 /*** architecture-dependent configuration *************************************/
68 /* first unset the macros (default) */
69 #undef REPLACE_RA_BETWEEN_FRAMES
70 #undef REPLACE_RA_TOP_OF_FRAME
71 #undef REPLACE_RA_LINKAGE_AREA
72 #undef REPLACE_LEAFMETHODS_RA_REGISTER
75 /* i386, x86_64 and m68k */
76 #if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
77 #define REPLACE_RA_BETWEEN_FRAMES
79 #elif defined(__ALPHA__)
80 #define REPLACE_RA_TOP_OF_FRAME
81 #define REPLACE_LEAFMETHODS_RA_REGISTER
82 #define REPLACE_REG_RA REG_RA
84 #elif defined(__POWERPC__)
85 #define REPLACE_RA_LINKAGE_AREA
86 #define REPLACE_LEAFMETHODS_RA_REGISTER
87 #define REPLACE_REG_RA REG_ITMP3 /* the execution state has the LR in itmp3 */
89 #elif defined(__S390__)
90 #define REPLACE_RA_TOP_OF_FRAME
91 #define REPLACE_REG_RA REG_ITMP3
95 /*** configuration of native stack slot size **********************************/
97 /* XXX this should be in md-abi.h files, probably */
99 #if defined(HAS_4BYTE_STACKSLOT)
100 #define SIZE_OF_STACKSLOT 4
101 #define STACK_SLOTS_PER_FLOAT 2
102 typedef u4 stackslot_t;
104 #define SIZE_OF_STACKSLOT 8
105 #define STACK_SLOTS_PER_FLOAT 1
106 typedef u8 stackslot_t;
110 /*** debugging ****************************************************************/
113 static void java_value_print(s4 type, replace_val_t value);
114 static void replace_stackframeinfo_println(stackframeinfo *sfi);
118 #define DOLOG(code) do{ if (opt_TraceReplacement > 1) { code; } } while(0)
119 #define DOLOG_SHORT(code) do{ if (opt_TraceReplacement > 0) { code; } } while(0)
122 #define DOLOG_SHORT(code)
126 /*** statistics ***************************************************************/
128 #define REPLACE_STATISTICS
130 #if defined(REPLACE_STATISTICS)
132 static int stat_replacements = 0;
133 static int stat_frames = 0;
134 static int stat_recompile = 0;
135 static int stat_staticpatch = 0;
136 static int stat_unroll_inline = 0;
137 static int stat_unroll_call = 0;
138 static int stat_dist_frames[20] = { 0 };
139 static int stat_dist_locals[20] = { 0 };
140 static int stat_dist_locals_adr[10] = { 0 };
141 static int stat_dist_locals_prim[10] = { 0 };
142 static int stat_dist_locals_ret[10] = { 0 };
143 static int stat_dist_locals_void[10] = { 0 };
144 static int stat_dist_stack[10] = { 0 };
145 static int stat_dist_stack_adr[10] = { 0 };
146 static int stat_dist_stack_prim[10] = { 0 };
147 static int stat_dist_stack_ret[10] = { 0 };
148 static int stat_methods = 0;
149 static int stat_rploints = 0;
150 static int stat_regallocs = 0;
151 static int stat_dist_method_rplpoints[20] = { 0 };
153 #define REPLACE_COUNT(cnt) (cnt)++
154 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
155 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
157 #define REPLACE_COUNT_DIST(array, val) \
159 int limit = (sizeof(array) / sizeof(int)) - 1; \
160 if ((val) < (limit)) (array)[val]++; \
161 else (array)[limit]++; \
164 static void replace_statistics_source_frame(sourceframe_t *frame);
168 #define REPLACE_COUNT(cnt)
169 #define REPLACE_COUNT_IF(cnt, cond)
170 #define REPLACE_COUNT_INC(cnt, inc)
171 #define REPLACE_COUNT_DIST(array, val)
173 #endif /* defined(REPLACE_STATISTICS) */
176 /*** constants used internally ************************************************/
178 #define TOP_IS_NORMAL 0
179 #define TOP_IS_ON_STACK 1
180 #define TOP_IS_IN_ITMP1 2
181 #define TOP_IS_VOID 3
184 /******************************************************************************/
185 /* PART I: Creating / freeing replacement points */
186 /******************************************************************************/
189 /* replace_create_replacement_point ********************************************
191 Create a replacement point.
194 jd...............current jitdata
195 iinfo............inlining info for the current position
196 rp...............pre-allocated (uninitialized) rplpoint
197 type.............RPLPOINT_TYPE constant
198 iptr.............current instruction
199 *pra.............current rplalloc pointer
200 javalocals.......the javalocals at the current point
201 stackvars........the stack variables at the current point
202 stackdepth.......the stack depth at the current point
203 paramcount.......number of parameters at the start of stackvars
206 *rpa.............points to the next free rplalloc
208 *******************************************************************************/
210 static void replace_create_replacement_point(jitdata *jd,
211 insinfo_inline *iinfo,
228 REPLACE_COUNT(stat_rploints);
230 rp->method = (iinfo) ? iinfo->method : jd->m;
231 rp->pc = NULL; /* set by codegen */
232 rp->callsize = 0; /* set by codegen */
236 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
238 /* XXX unify these two fields */
239 rp->parent = (iinfo) ? iinfo->rp : NULL;
241 /* store local allocation info of javalocals */
244 for (i = 0; i < rp->method->maxlocals; ++i) {
245 index = javalocals[i];
252 ra->flags = v->flags & (INMEMORY);
253 ra->regoff = v->vv.regoff;
257 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
265 /* store allocation info of java stack vars */
267 for (i = 0; i < stackdepth; ++i) {
268 v = VAR(stackvars[i]);
269 ra->flags = v->flags & (INMEMORY);
270 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
272 /* XXX how to handle locals on the stack containing returnAddresses? */
273 if (v->type == TYPE_RET) {
274 assert(stackvars[i] >= jd->localcount);
275 ra->regoff = v->vv.retaddr->nr;
278 ra->regoff = v->vv.regoff;
282 /* total number of allocations */
284 rp->regalloccount = ra - rp->regalloc;
290 /* replace_create_inline_start_replacement_point *******************************
292 Create an INLINE_START replacement point.
295 jd...............current jitdata
296 rp...............pre-allocated (uninitialized) rplpoint
297 iptr.............current instruction
298 *pra.............current rplalloc pointer
299 javalocals.......the javalocals at the current point
302 *rpa.............points to the next free rplalloc
305 the insinfo_inline * for the following inlined body
307 *******************************************************************************/
309 static insinfo_inline * replace_create_inline_start_replacement_point(
316 insinfo_inline *calleeinfo;
319 calleeinfo = iptr->sx.s23.s3.inlineinfo;
323 replace_create_replacement_point(jd, calleeinfo->parent, rp,
324 RPLPOINT_TYPE_INLINE, iptr, pra,
326 calleeinfo->stackvars, calleeinfo->stackvarscount,
327 calleeinfo->paramcount);
329 if (calleeinfo->synclocal != UNUSED) {
331 ra->index = RPLALLOC_SYNC;
332 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
333 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
343 /* replace_create_replacement_points *******************************************
345 Create the replacement points for the given code.
348 jd...............current jitdata, must not have any replacement points
351 code->rplpoints.......set to the list of replacement points
352 code->rplpointcount...number of replacement points
353 code->regalloc........list of allocation info
354 code->regalloccount...total length of allocation info list
355 code->globalcount.....number of global allocations at the
356 start of code->regalloc
359 true.............everything ok
360 false............an exception has been thrown
362 *******************************************************************************/
364 #define CLEAR_javalocals(array, method) \
366 for (i=0; i<(method)->maxlocals; ++i) \
367 (array)[i] = UNUSED; \
370 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
372 if ((array) != NULL) \
373 MCOPY((dest), (array), s4, (method)->maxlocals); \
375 CLEAR_javalocals((dest), (method)); \
378 #define COUNT_javalocals(array, method, counter) \
380 for (i=0; i<(method)->maxlocals; ++i) \
381 if ((array)[i] != UNUSED) \
385 bool replace_create_replacement_points(jitdata *jd)
403 insinfo_inline *iinfo;
406 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
410 REPLACE_COUNT(stat_methods);
412 /* get required compiler data */
417 /* assert that we wont overwrite already allocated data */
421 assert(code->rplpoints == NULL);
422 assert(code->rplpointcount == 0);
423 assert(code->regalloc == NULL);
424 assert(code->regalloccount == 0);
425 assert(code->globalcount == 0);
429 /* set codeinfo flags */
431 if (jd->isleafmethod)
432 CODE_SETFLAG_LEAFMETHOD(code);
434 /* in instance methods, we may need a rplpoint at the method entry */
436 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
437 if (!(m->flags & ACC_STATIC)) {
438 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
444 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
446 /* iterate over the basic block list to find replacement points */
451 javalocals = DMNEW(s4, jd->maxlocals);
453 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
457 if (bptr->flags < BBFINISHED)
460 /* get info about this block */
463 iinfo = bptr->inlineinfo;
465 /* initialize javalocals at the start of this block */
467 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
469 /* iterate over the instructions */
472 iend = iptr + bptr->icount;
476 for (; iptr != iend; ++iptr) {
478 case ICMD_INVOKESTATIC:
479 case ICMD_INVOKESPECIAL:
480 case ICMD_INVOKEVIRTUAL:
481 case ICMD_INVOKEINTERFACE:
482 INSTRUCTION_GET_METHODDESC(iptr, md);
484 COUNT_javalocals(javalocals, m, alloccount);
485 alloccount += iptr->s1.argcount;
487 alloccount -= iinfo->throughcount;
495 stack_javalocals_store(iptr, javalocals);
509 case ICMD_INLINE_START:
510 iinfo = iptr->sx.s23.s3.inlineinfo;
513 COUNT_javalocals(javalocals, m, alloccount);
514 alloccount += iinfo->stackvarscount;
515 if (iinfo->synclocal != UNUSED)
519 /* javalocals may be set at next block start, or now */
520 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
523 case ICMD_INLINE_BODY:
524 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
526 jl = iinfo->javalocals_start;
528 /* get the javalocals from the following block start */
530 jl = bptr->next->javalocals;
533 COUNT_javalocals(jl, m, alloccount);
536 case ICMD_INLINE_END:
537 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
538 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
539 iinfo = iptr->sx.s23.s3.inlineinfo;
541 if (iinfo->javalocals_end)
542 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
543 iinfo = iinfo->parent;
547 if (iptr == bptr->iinstr)
549 } /* end instruction loop */
551 /* create replacement points at targets of backward branches */
552 /* We only need the replacement point there, if there is no */
553 /* replacement point inside the block. */
555 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
556 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
557 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
561 if (test > startcount) {
562 /* we don't need an extra rplpoint */
563 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
567 alloccount += bptr->indepth;
568 if (bptr->inlineinfo)
569 alloccount -= bptr->inlineinfo->throughcount;
571 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
575 } /* end basicblock loop */
577 /* if no points were found, there's nothing to do */
582 /* allocate replacement point array and allocation array */
584 rplpoints = MNEW(rplpoint, count);
585 regalloc = MNEW(rplalloc, alloccount);
588 /* initialize replacement point structs */
592 /* XXX try to share code with the counting loop! */
594 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
597 if (bptr->flags < BBFINISHED)
600 /* get info about this block */
603 iinfo = bptr->inlineinfo;
605 /* initialize javalocals at the start of this block */
607 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
609 /* create replacement points at targets of backward branches */
611 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
613 i = (iinfo) ? iinfo->throughcount : 0;
614 replace_create_replacement_point(jd, iinfo, rp++,
615 bptr->type, bptr->iinstr, &ra,
616 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
618 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
619 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
622 /* iterate over the instructions */
625 iend = iptr + bptr->icount;
627 for (; iptr != iend; ++iptr) {
629 case ICMD_INVOKESTATIC:
630 case ICMD_INVOKESPECIAL:
631 case ICMD_INVOKEVIRTUAL:
632 case ICMD_INVOKEINTERFACE:
633 INSTRUCTION_GET_METHODDESC(iptr, md);
635 i = (iinfo) ? iinfo->throughcount : 0;
636 replace_create_replacement_point(jd, iinfo, rp++,
637 RPLPOINT_TYPE_CALL, iptr, &ra,
638 javalocals, iptr->sx.s23.s2.args,
639 iptr->s1.argcount - i,
648 stack_javalocals_store(iptr, javalocals);
656 replace_create_replacement_point(jd, iinfo, rp++,
657 RPLPOINT_TYPE_RETURN, iptr, &ra,
658 NULL, &(iptr->s1.varindex), 1, 0);
662 replace_create_replacement_point(jd, iinfo, rp++,
663 RPLPOINT_TYPE_RETURN, iptr, &ra,
667 case ICMD_INLINE_START:
668 iinfo = replace_create_inline_start_replacement_point(
669 jd, rp++, iptr, &ra, javalocals);
671 /* javalocals may be set at next block start, or now */
672 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
675 case ICMD_INLINE_BODY:
676 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
678 jl = iinfo->javalocals_start;
680 /* get the javalocals from the following block start */
682 jl = bptr->next->javalocals;
684 /* create a non-trappable rplpoint */
685 replace_create_replacement_point(jd, iinfo, rp++,
686 RPLPOINT_TYPE_BODY, iptr, &ra,
688 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
691 case ICMD_INLINE_END:
692 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
693 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
694 iinfo = iptr->sx.s23.s3.inlineinfo;
696 if (iinfo->javalocals_end)
697 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
698 iinfo = iinfo->parent;
701 } /* end instruction loop */
702 } /* end basicblock loop */
704 assert((rp - rplpoints) == count);
705 assert((ra - regalloc) == alloccount);
707 /* store the data in the codeinfo */
709 code->rplpoints = rplpoints;
710 code->rplpointcount = count;
711 code->regalloc = regalloc;
712 code->regalloccount = alloccount;
713 code->globalcount = 0;
714 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
715 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
716 #if defined(HAS_ADDRESS_REGISTER_FILE)
717 code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
719 code->memuse = rd->memuse;
720 code->stackframesize = jd->cd->stackframesize;
722 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
723 REPLACE_COUNT_INC(stat_regallocs, alloccount);
725 /* everything alright */
731 /* replace_free_replacement_points *********************************************
733 Free memory used by replacement points.
736 code.............codeinfo whose replacement points should be freed.
738 *******************************************************************************/
740 void replace_free_replacement_points(codeinfo *code)
745 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
748 MFREE(code->regalloc,rplalloc,code->regalloccount);
750 code->rplpoints = NULL;
751 code->rplpointcount = 0;
752 code->regalloc = NULL;
753 code->regalloccount = 0;
754 code->globalcount = 0;
758 /******************************************************************************/
759 /* PART II: Activating / deactivating replacement points */
760 /******************************************************************************/
763 /* replace_activate_replacement_points *****************************************
765 Activate the replacement points of the given compilation unit. When this
766 function returns, the replacement points are "armed", so each thread
767 reaching one of the points will enter the replacement mechanism.
770 code.............codeinfo of which replacement points should be
772 mappable.........if true, only mappable replacement points are
775 *******************************************************************************/
777 void replace_activate_replacement_points(codeinfo *code, bool mappable)
785 assert(code->savedmcode == NULL);
787 /* count trappable replacement points */
791 i = code->rplpointcount;
792 rp = code->rplpoints;
794 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
799 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
805 /* allocate buffer for saved machine code */
807 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
808 code->savedmcode = savedmcode;
809 savedmcode += count * REPLACEMENT_PATCH_SIZE;
811 /* activate trappable replacement points */
812 /* (in reverse order to handle overlapping points within basic blocks) */
814 i = code->rplpointcount;
815 rp = code->rplpoints + i;
817 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
819 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
824 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
827 DOLOG( printf("activate replacement point:\n");
828 replace_replacement_point_println(rp, 1); fflush(stdout); );
830 savedmcode -= REPLACEMENT_PATCH_SIZE;
832 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
833 md_patch_replacement_point(code, index, rp, savedmcode);
835 rp->flags |= RPLPOINT_FLAG_ACTIVE;
838 assert(savedmcode == code->savedmcode);
842 /* replace_deactivate_replacement_points ***************************************
844 Deactivate a replacement points in the given compilation unit.
845 When this function returns, the replacement points will be "un-armed",
846 that is a each thread reaching a point will just continue normally.
849 code.............the compilation unit
851 *******************************************************************************/
853 void replace_deactivate_replacement_points(codeinfo *code)
860 if (code->savedmcode == NULL) {
861 /* disarm countdown points by patching the branches */
863 i = code->rplpointcount;
864 rp = code->rplpoints;
866 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
867 == RPLPOINT_FLAG_COUNTDOWN)
870 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
877 assert(code->savedmcode != NULL);
878 savedmcode = code->savedmcode;
880 /* de-activate each trappable replacement point */
882 i = code->rplpointcount;
883 rp = code->rplpoints;
886 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
891 DOLOG( printf("deactivate replacement point:\n");
892 replace_replacement_point_println(rp, 1); fflush(stdout); );
894 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
895 md_patch_replacement_point(code, -1, rp, savedmcode);
898 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
900 savedmcode += REPLACEMENT_PATCH_SIZE;
903 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
905 /* free saved machine code */
907 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
908 code->savedmcode = NULL;
912 /******************************************************************************/
913 /* PART III: The replacement mechanism */
914 /******************************************************************************/
917 /* replace_read_value **********************************************************
919 Read a value with the given allocation from the execution state.
922 es...............execution state
923 ra...............allocation
924 javaval..........where to put the value
927 *javaval.........the value
929 *******************************************************************************/
931 static void replace_read_value(executionstate_t *es,
933 replace_val_t *javaval)
935 if (ra->flags & INMEMORY) {
936 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
937 #ifdef HAS_4BYTE_STACKSLOT
938 if (IS_2_WORD_TYPE(ra->type)) {
939 javaval->l = *(u8*)(es->sp + ra->regoff);
943 javaval->p = *(ptrint*)(es->sp + ra->regoff);
944 #ifdef HAS_4BYTE_STACKSLOT
949 /* allocated register */
950 if (IS_FLT_DBL_TYPE(ra->type)) {
951 javaval->d = es->fltregs[ra->regoff];
953 if (ra->type == TYPE_FLT)
954 javaval->f = javaval->d;
956 #if defined(HAS_ADDRESS_REGISTER_FILE)
957 else if (IS_ADR_TYPE(ra->type)) {
958 javaval->p = es->adrregs[ra->regoff];
962 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
963 if (ra->type == TYPE_LNG) {
964 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
965 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
968 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
969 javaval->p = es->intregs[ra->regoff];
975 /* replace_write_value *********************************************************
977 Write a value to the given allocation in the execution state.
980 es...............execution state
981 ra...............allocation
982 *javaval.........the value
984 *******************************************************************************/
986 static void replace_write_value(executionstate_t *es,
988 replace_val_t *javaval)
990 if (ra->flags & INMEMORY) {
991 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
992 #ifdef HAS_4BYTE_STACKSLOT
993 if (IS_2_WORD_TYPE(ra->type)) {
994 *(u8*)(es->sp + ra->regoff) = javaval->l;
998 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
999 #ifdef HAS_4BYTE_STACKSLOT
1004 /* allocated register */
1007 es->fltregs[ra->regoff] = (double) javaval->f;
1010 es->fltregs[ra->regoff] = javaval->d;
1012 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1014 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1015 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1018 #if defined(HAS_ADDRESS_REGISTER_FILE)
1020 es->adrregs[ra->regoff] = javaval->p;
1023 es->intregs[ra->regoff] = javaval->p;
1029 /* replace_new_sourceframe *****************************************************
1031 Allocate a new source frame and insert it at the front of the frame list.
1034 ss...............the source state
1037 ss->frames.......set to new frame (the new head of the frame list).
1040 returns the new frame
1042 *******************************************************************************/
1044 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1046 sourceframe_t *frame;
1048 frame = DNEW(sourceframe_t);
1049 MZERO(frame, sourceframe_t, 1);
1051 frame->down = ss->frames;
1058 /* replace_read_executionstate *************************************************
1060 Read a source frame from the given executions state.
1061 The new source frame is pushed to the front of the frame list of the
1065 rp...............replacement point at which `es` was taken
1066 es...............execution state
1067 ss...............the source state to add the source frame to
1068 topframe.........true, if the first (top-most) source frame on the
1072 *ss..............the source state with the newly created source frame
1075 *******************************************************************************/
1077 static s4 replace_normalize_type_map[] = {
1078 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1079 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1080 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1081 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1082 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1083 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1084 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1088 static void replace_read_executionstate(rplpoint *rp,
1089 executionstate_t *es,
1098 sourceframe_t *frame;
1101 stackslot_t *basesp;
1103 code = code_find_codeinfo_for_pc(rp->pc);
1105 topslot = TOP_IS_NORMAL;
1109 sp = (stackslot_t *) es->sp;
1111 /* in some cases the top stack slot is passed in REG_ITMP1 */
1113 if (rp->type == BBTYPE_EXH) {
1114 topslot = TOP_IS_IN_ITMP1;
1117 /* calculate base stack pointer */
1119 basesp = sp + code->stackframesize;
1121 /* create the source frame */
1123 frame = replace_new_sourceframe(ss);
1124 frame->method = rp->method;
1126 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1127 frame->type = replace_normalize_type_map[rp->type];
1129 frame->fromcode = code;
1131 /* read local variables */
1133 count = m->maxlocals;
1134 frame->javalocalcount = count;
1135 frame->javalocals = DMNEW(replace_val_t, count);
1136 frame->javalocaltype = DMNEW(u1, count);
1138 /* mark values as undefined */
1139 for (i=0; i<count; ++i) {
1140 #if !defined(NDEBUG)
1141 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1143 frame->javalocaltype[i] = TYPE_VOID;
1146 /* some entries in the intregs array are not meaningful */
1147 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1148 #if !defined(NDEBUG)
1149 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1151 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1153 #endif /* !defined(NDEBUG) */
1155 /* read javalocals */
1157 count = rp->regalloccount;
1160 while (count && (i = ra->index) >= 0) {
1161 assert(i < m->maxlocals);
1162 frame->javalocaltype[i] = ra->type;
1163 if (ra->type == TYPE_RET)
1164 frame->javalocals[i].i = ra->regoff;
1166 replace_read_value(es, ra, frame->javalocals + i);
1171 /* read instance, if this is the first rplpoint */
1173 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1174 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1176 /* we are at the start of the method body, so if local 0 is set, */
1177 /* it is the instance. */
1178 if (frame->javalocaltype[0] == TYPE_ADR)
1179 frame->instance = frame->javalocals[0];
1184 md = rp->method->parseddesc;
1186 assert(md->paramcount >= 1);
1187 instra.type = TYPE_ADR;
1188 instra.regoff = md->params[0].regoff;
1189 if (md->params[0].inmemory) {
1190 instra.flags = INMEMORY;
1191 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1196 replace_read_value(es, &instra, &(frame->instance));
1199 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1201 /* read stack slots */
1203 frame->javastackdepth = count;
1204 frame->javastack = DMNEW(replace_val_t, count);
1205 frame->javastacktype = DMNEW(u1, count);
1207 #if !defined(NDEBUG)
1208 /* mark values as undefined */
1209 for (i=0; i<count; ++i) {
1210 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1211 frame->javastacktype[i] = TYPE_VOID;
1213 #endif /* !defined(NDEBUG) */
1217 /* the first stack slot is special in SBR and EXH blocks */
1219 if (topslot == TOP_IS_ON_STACK) {
1222 assert(ra->index == RPLALLOC_STACK);
1223 assert(ra->type == TYPE_ADR);
1224 frame->javastack[i].p = sp[-1];
1225 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1230 else if (topslot == TOP_IS_IN_ITMP1) {
1233 assert(ra->index == RPLALLOC_STACK);
1234 assert(ra->type == TYPE_ADR);
1235 frame->javastack[i].p = es->intregs[REG_ITMP1];
1236 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1241 else if (topslot == TOP_IS_VOID) {
1244 assert(ra->index == RPLALLOC_STACK);
1245 frame->javastack[i].l = 0;
1246 frame->javastacktype[i] = TYPE_VOID;
1252 /* read remaining stack slots */
1254 for (; count--; ra++) {
1255 if (ra->index == RPLALLOC_SYNC) {
1256 assert(rp->type == RPLPOINT_TYPE_INLINE);
1258 /* only read synchronization slots when traversing an inline point */
1261 sourceframe_t *calleeframe = frame->down;
1262 assert(calleeframe);
1263 assert(calleeframe->syncslotcount == 0);
1264 assert(calleeframe->syncslots == NULL);
1266 calleeframe->syncslotcount = 1;
1267 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1268 replace_read_value(es,ra,calleeframe->syncslots);
1271 frame->javastackdepth--;
1275 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1277 /* do not read parameters of calls down the call chain */
1279 if (!topframe && ra->index == RPLALLOC_PARAM) {
1280 frame->javastackdepth--;
1283 if (ra->type == TYPE_RET)
1284 frame->javastack[i].i = ra->regoff;
1286 replace_read_value(es,ra,frame->javastack + i);
1287 frame->javastacktype[i] = ra->type;
1294 /* replace_write_executionstate ************************************************
1296 Pop a source frame from the front of the frame list of the given source state
1297 and write its values into the execution state.
1300 rp...............replacement point for which execution state should be
1302 es...............the execution state to modify
1303 ss...............the given source state
1304 topframe.........true, if this is the last (top-most) source frame to be
1308 *es..............the execution state derived from the source state
1310 *******************************************************************************/
1312 static void replace_write_executionstate(rplpoint *rp,
1313 executionstate_t *es,
1322 sourceframe_t *frame;
1325 stackslot_t *basesp;
1327 code = code_find_codeinfo_for_pc(rp->pc);
1329 topslot = TOP_IS_NORMAL;
1331 /* pop a source frame */
1335 ss->frames = frame->down;
1337 /* calculate stack pointer */
1339 sp = (stackslot_t *) es->sp;
1341 basesp = sp + code->stackframesize;
1343 /* in some cases the top stack slot is passed in REG_ITMP1 */
1345 if (rp->type == BBTYPE_EXH) {
1346 topslot = TOP_IS_IN_ITMP1;
1349 /* write javalocals */
1352 count = rp->regalloccount;
1354 while (count && (i = ra->index) >= 0) {
1355 assert(i < m->maxlocals);
1356 assert(i < frame->javalocalcount);
1357 assert(ra->type == frame->javalocaltype[i]);
1358 if (ra->type == TYPE_RET) {
1359 /* XXX assert that it matches this rplpoint */
1362 replace_write_value(es, ra, frame->javalocals + i);
1367 /* write stack slots */
1371 /* the first stack slot is special in SBR and EXH blocks */
1373 if (topslot == TOP_IS_ON_STACK) {
1376 assert(ra->index == RPLALLOC_STACK);
1377 assert(i < frame->javastackdepth);
1378 assert(frame->javastacktype[i] == TYPE_ADR);
1379 sp[-1] = frame->javastack[i].p;
1384 else if (topslot == TOP_IS_IN_ITMP1) {
1387 assert(ra->index == RPLALLOC_STACK);
1388 assert(i < frame->javastackdepth);
1389 assert(frame->javastacktype[i] == TYPE_ADR);
1390 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1395 else if (topslot == TOP_IS_VOID) {
1398 assert(ra->index == RPLALLOC_STACK);
1399 assert(i < frame->javastackdepth);
1400 assert(frame->javastacktype[i] == TYPE_VOID);
1406 /* write remaining stack slots */
1408 for (; count--; ra++) {
1409 if (ra->index == RPLALLOC_SYNC) {
1410 assert(rp->type == RPLPOINT_TYPE_INLINE);
1412 /* only write synchronization slots when traversing an inline point */
1415 assert(frame->down);
1416 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1417 assert(frame->down->syncslots != NULL);
1419 replace_write_value(es,ra,frame->down->syncslots);
1424 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1426 /* do not write parameters of calls down the call chain */
1428 if (!topframe && ra->index == RPLALLOC_PARAM) {
1432 assert(i < frame->javastackdepth);
1433 assert(ra->type == frame->javastacktype[i]);
1434 if (ra->type == TYPE_RET) {
1435 /* XXX assert that it matches this rplpoint */
1438 replace_write_value(es,ra,frame->javastack + i);
1450 /* replace_pop_activation_record ***********************************************
1452 Peel a stack frame from the execution state.
1454 *** This function imitates the effects of the method epilog ***
1455 *** and returning from the method call. ***
1458 es...............execution state
1459 frame............source frame, receives synchronization slots
1462 *es..............the execution state after popping the stack frame
1464 *******************************************************************************/
1466 u1* replace_pop_activation_record(executionstate_t *es,
1467 sourceframe_t *frame)
1475 stackslot_t *basesp;
1481 /* read the return address */
1483 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1484 if (CODE_IS_LEAFMETHOD(es->code))
1485 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1488 ra = md_stacktrace_get_returnaddress(es->sp,
1489 SIZE_OF_STACKSLOT * es->code->stackframesize);
1491 DOLOG( printf("return address: %p\n", (void*)ra); );
1495 /* calculate the base of the stack frame */
1497 sp = (stackslot_t *) es->sp;
1498 basesp = sp + es->code->stackframesize;
1500 /* read slots used for synchronization */
1502 assert(frame->syncslotcount == 0);
1503 assert(frame->syncslots == NULL);
1504 count = code_get_sync_slot_count(es->code);
1505 frame->syncslotcount = count;
1506 frame->syncslots = DMNEW(replace_val_t, count);
1507 for (i=0; i<count; ++i) {
1508 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1511 /* restore return address, if part of frame */
1513 #if defined(REPLACE_RA_TOP_OF_FRAME)
1514 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1515 if (!CODE_IS_LEAFMETHOD(es->code))
1517 es->intregs[REPLACE_REG_RA] = *--basesp;
1518 #endif /* REPLACE_RA_TOP_OF_FRAME */
1520 #if defined(REPLACE_RA_LINKAGE_AREA)
1521 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1522 if (!CODE_IS_LEAFMETHOD(es->code))
1524 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1525 #endif /* REPLACE_RA_LINKAGE_AREA */
1527 /* restore saved int registers */
1530 for (i=0; i<es->code->savedintcount; ++i) {
1531 while (nregdescint[--reg] != REG_SAV)
1533 es->intregs[reg] = *--basesp;
1536 /* restore saved flt registers */
1540 for (i=0; i<es->code->savedfltcount; ++i) {
1541 while (nregdescfloat[--reg] != REG_SAV)
1543 basesp -= STACK_SLOTS_PER_FLOAT;
1544 es->fltregs[reg] = *(double*)basesp;
1547 #if defined(HAS_ADDRESS_REGISTER_FILE)
1548 /* restore saved adr registers */
1551 for (i=0; i<es->code->savedadrcount; ++i) {
1552 while (nregdescadr[--reg] != REG_SAV)
1554 es->adrregs[reg] = *--basesp;
1558 /* adjust the stackpointer */
1560 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1562 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1563 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1566 /* Set the new pc. Subtract one so we do not hit the replacement point */
1567 /* of the instruction following the call, if there is one. */
1571 /* find the new codeinfo */
1573 pv = md_codegen_get_pv_from_pc(ra);
1575 DOLOG( printf("PV = %p\n", (void*) pv); );
1577 if (pv == NULL) /* XXX can this really happen? */
1580 code = *(codeinfo **)(pv + CodeinfoPointer);
1582 DOLOG( printf("CODE = %p\n", (void*) code); );
1584 /* return NULL if we reached native code */
1589 /* in debugging mode clobber non-saved registers */
1591 #if !defined(NDEBUG)
1593 for (i=0; i<INT_REG_CNT; ++i)
1594 if ((nregdescint[i] != REG_SAV)
1596 && (i != REPLACE_REG_RA)
1599 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1600 for (i=0; i<FLT_REG_CNT; ++i)
1601 if (nregdescfloat[i] != REG_SAV)
1602 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1603 # if defined(HAS_ADDRESS_REGISTER_FILE)
1604 for (i=0; i<ADR_REG_CNT; ++i)
1605 if (nregdescadr[i] != REG_SAV)
1606 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1608 #endif /* !defined(NDEBUG) */
1610 return (code) ? ra : NULL;
1614 /* replace_patch_method_pointer ************************************************
1616 Patch a method pointer (may be in code, data segment, vftbl, or interface
1620 mpp..............address of the method pointer to patch
1621 entrypoint.......the new entrypoint of the method
1622 kind.............kind of call to patch, used only for debugging
1624 *******************************************************************************/
1626 static void replace_patch_method_pointer(methodptr *mpp,
1627 methodptr entrypoint,
1630 #if !defined(NDEBUG)
1635 DOLOG( printf("patch method pointer from: %p to %p\n",
1636 (void*) *mpp, (void*)entrypoint); );
1638 #if !defined(NDEBUG)
1639 oldcode = *(codeinfo **)((u1*)(*mpp) + CodeinfoPointer);
1640 newcode = *(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer);
1642 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1643 method_println(oldcode->m);
1644 printf("\t with %p ", (void*) newcode);
1645 method_println(newcode->m); );
1647 assert(oldcode->m == newcode->m);
1650 /* write the new entrypoint */
1652 *mpp = (methodptr) entrypoint;
1656 /* replace_patch_class *********************************************************
1658 Patch a method in the given class.
1661 vftbl............vftbl of the class
1662 m................the method to patch
1663 oldentrypoint....the old entrypoint to replace
1664 entrypoint.......the new entrypoint
1666 *******************************************************************************/
1668 void replace_patch_class(vftbl_t *vftbl,
1677 /* patch the vftbl of the class */
1679 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1683 /* patch the interface tables */
1685 assert(oldentrypoint);
1687 for (i=0; i < vftbl->interfacetablelength; ++i) {
1688 mpp = vftbl->interfacetable[-i];
1689 mppend = mpp + vftbl->interfacevftbllength[i];
1690 for (; mpp != mppend; ++mpp)
1691 if (*mpp == oldentrypoint) {
1692 replace_patch_method_pointer(mpp, entrypoint, "interface");
1698 /* replace_patch_class_hierarchy ***********************************************
1700 Patch a method in all loaded classes.
1703 m................the method to patch
1704 oldentrypoint....the old entrypoint to replace
1705 entrypoint.......the new entrypoint
1707 *******************************************************************************/
1709 struct replace_patch_data_t {
1715 #define CODEINFO_OF_CODE(entrypoint) \
1716 (*(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer))
1718 #define METHOD_OF_CODE(entrypoint) \
1719 (CODEINFO_OF_CODE(entrypoint)->m)
1721 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1723 vftbl_t *vftbl = c->vftbl;
1726 && vftbl->vftbllength > pd->m->vftblindex
1727 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1728 && METHOD_OF_CODE(vftbl->table[pd->m->vftblindex]) == pd->m)
1730 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1734 void replace_patch_class_hierarchy(methodinfo *m,
1738 struct replace_patch_data_t pd;
1741 pd.oldentrypoint = oldentrypoint;
1742 pd.entrypoint = entrypoint;
1744 DOLOG_SHORT( printf("patching class hierarchy: ");
1745 method_println(m); );
1747 classcache_foreach_loaded_class(
1748 (classcache_foreach_functionptr_t) &replace_patch_callback,
1753 /* replace_patch_future_calls **************************************************
1755 Analyse a call site and depending on the kind of call patch the call, the
1756 virtual function table, or the interface table.
1759 ra...............return address pointing after the call site
1760 callerframe......source frame of the caller
1761 calleeframe......source frame of the callee, must have been mapped
1763 *******************************************************************************/
1765 void replace_patch_future_calls(u1 *ra,
1766 sourceframe_t *callerframe,
1767 sourceframe_t *calleeframe)
1770 methodptr entrypoint;
1771 methodptr oldentrypoint;
1774 codeinfo *calleecode;
1775 methodinfo *calleem;
1780 assert(callerframe->down == calleeframe);
1782 /* get the new codeinfo and the method that shall be entered */
1784 calleecode = calleeframe->tocode;
1787 calleem = calleeframe->method;
1788 assert(calleem == calleecode->m);
1790 entrypoint = (methodptr) calleecode->entrypoint;
1792 /* check if we are at an method entry rplpoint at the innermost frame */
1794 atentry = (calleeframe->down == NULL)
1795 && !(calleem->flags & ACC_STATIC)
1796 && (calleeframe->fromrp->id == 0); /* XXX */
1798 /* get the position to patch, in case it was a statically bound call */
1800 sfi.pv = callerframe->fromcode->entrypoint;
1801 patchpos = md_get_method_patch_address(ra, &sfi, NULL);
1803 if (patchpos == NULL) {
1804 /* the call was dispatched dynamically */
1806 /* we can only patch such calls if we are at the entry point */
1811 assert((calleem->flags & ACC_STATIC) == 0);
1813 oldentrypoint = calleeframe->fromcode->entrypoint;
1815 /* we need to know the instance */
1817 if (!calleeframe->instance.a) {
1818 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1819 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1825 obj = calleeframe->instance.a;
1828 assert(vftbl->class->vftbl == vftbl);
1830 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1832 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1835 /* the call was statically bound */
1837 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1842 /* replace_push_activation_record **********************************************
1844 Push a stack frame onto the execution state.
1846 *** This function imitates the effects of a call and the ***
1847 *** method prolog of the callee. ***
1850 es...............execution state
1851 rpcall...........the replacement point at the call site
1852 callerframe......source frame of the caller, or NULL for creating the
1854 calleeframe......source frame of the callee, must have been mapped
1857 *es..............the execution state after pushing the stack frame
1859 *******************************************************************************/
1861 void replace_push_activation_record(executionstate_t *es,
1863 sourceframe_t *callerframe,
1864 sourceframe_t *calleeframe)
1869 stackslot_t *basesp;
1872 codeinfo *calleecode;
1875 assert(!rpcall || callerframe);
1876 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1877 assert(!rpcall || rpcall == callerframe->torp);
1878 assert(calleeframe);
1879 assert(!callerframe || calleeframe == callerframe->down);
1881 /* the compilation unit we are entering */
1883 calleecode = calleeframe->tocode;
1886 /* calculate the return address */
1889 ra = rpcall->pc + rpcall->callsize;
1891 ra = es->pc + 1 /* XXX this is ugly */;
1893 /* write the return address */
1895 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1896 es->sp -= SIZE_OF_STACKSLOT;
1898 *((stackslot_t *)es->sp) = (stackslot_t) ra;
1899 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1901 #if defined(REPLACE_REG_RA)
1902 es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1905 /* we move into a new code unit */
1907 es->code = calleecode;
1909 /* set the new pc XXX not needed? */
1911 es->pc = calleecode->entrypoint;
1913 /* build the stackframe */
1915 DOLOG( printf("building stackframe of %d words at %p\n",
1916 calleecode->stackframesize, (void*)es->sp); );
1918 sp = (stackslot_t *) es->sp;
1921 sp -= calleecode->stackframesize;
1924 /* in debug mode, invalidate stack frame first */
1926 /* XXX may not invalidate linkage area used by native code! */
1927 #if !defined(NDEBUG) && 0
1928 for (i=0; i<(basesp - sp); ++i) {
1929 sp[i] = 0xdeaddeadU;
1933 /* save the return address register */
1935 #if defined(REPLACE_RA_TOP_OF_FRAME)
1936 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1937 if (!CODE_IS_LEAFMETHOD(calleecode))
1939 *--basesp = (ptrint) ra;
1940 #endif /* REPLACE_RA_TOP_OF_FRAME */
1942 #if defined(REPLACE_RA_LINKAGE_AREA)
1943 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1944 if (!CODE_IS_LEAFMETHOD(calleecode))
1946 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1947 #endif /* REPLACE_RA_LINKAGE_AREA */
1949 /* save int registers */
1952 for (i=0; i<calleecode->savedintcount; ++i) {
1953 while (nregdescint[--reg] != REG_SAV)
1955 *--basesp = es->intregs[reg];
1957 /* XXX may not clobber saved regs used by native code! */
1958 #if !defined(NDEBUG) && 0
1959 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1963 /* save flt registers */
1967 for (i=0; i<calleecode->savedfltcount; ++i) {
1968 while (nregdescfloat[--reg] != REG_SAV)
1970 basesp -= STACK_SLOTS_PER_FLOAT;
1971 *(double*)basesp = es->fltregs[reg];
1973 /* XXX may not clobber saved regs used by native code! */
1974 #if !defined(NDEBUG) && 0
1975 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1979 #if defined(HAS_ADDRESS_REGISTER_FILE)
1980 /* save adr registers */
1983 for (i=0; i<calleecode->savedadrcount; ++i) {
1984 while (nregdescadr[--reg] != REG_SAV)
1986 *--basesp = es->adrregs[reg];
1988 /* XXX may not clobber saved regs used by native code! */
1989 #if !defined(NDEBUG) && 0
1990 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1995 /* write slots used for synchronization */
1997 count = code_get_sync_slot_count(calleecode);
1998 assert(count == calleeframe->syncslotcount);
1999 for (i=0; i<count; ++i) {
2000 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2005 es->pv = calleecode->entrypoint;
2007 /* redirect future invocations */
2009 if (callerframe && rpcall) {
2010 #if defined(REPLACE_PATCH_ALL)
2011 if (rpcall->type == callerframe->fromrp->type)
2013 if (rpcall == callerframe->fromrp)
2015 replace_patch_future_calls(ra, callerframe, calleeframe);
2020 /* replace_find_replacement_point **********************************************
2022 Find the replacement point in the given code corresponding to the
2023 position given in the source frame.
2026 code.............the codeinfo in which to search the rplpoint
2027 frame............the source frame defining the position to look for
2028 parent...........parent replacement point to match
2031 the replacement point
2033 *******************************************************************************/
2035 rplpoint * replace_find_replacement_point(codeinfo *code,
2036 sourceframe_t *frame,
2049 DOLOG( printf("searching replacement point for:\n");
2050 replace_source_frame_println(frame); );
2054 DOLOG( printf("code = %p\n", (void*)code); );
2056 rp = code->rplpoints;
2057 i = code->rplpointcount;
2059 if (rp->id == frame->id && rp->method == frame->method
2060 && rp->parent == parent
2061 && replace_normalize_type_map[rp->type] == frame->type)
2063 /* check if returnAddresses match */
2064 /* XXX optimize: only do this if JSRs in method */
2065 DOLOG( printf("checking match for:");
2066 replace_replacement_point_println(rp, 1); fflush(stdout); );
2069 for (j = rp->regalloccount; j--; ++ra) {
2070 if (ra->type == TYPE_RET) {
2071 if (ra->index == RPLALLOC_STACK) {
2072 assert(stacki < frame->javastackdepth);
2073 if (frame->javastack[stacki].i != ra->regoff)
2078 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2079 if (frame->javalocals[ra->index].i != ra->regoff)
2092 #if !defined(NDEBUG)
2093 printf("candidate replacement points were:\n");
2094 rp = code->rplpoints;
2095 i = code->rplpointcount;
2097 replace_replacement_point_println(rp, 1);
2101 vm_abort("no matching replacement point found");
2102 return NULL; /* NOT REACHED */
2106 /* replace_find_replacement_point_for_pc ***************************************
2108 Find the nearest replacement point at or before the given PC.
2111 code.............compilation unit the PC is in
2112 pc...............the machine code PC
2115 the replacement point found, or
2116 NULL if no replacement point was found
2118 *******************************************************************************/
2120 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2126 DOLOG( printf("searching for rp in %p ", (void*)code);
2127 method_println(code->m); );
2131 rp = code->rplpoints;
2132 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2133 DOLOG( replace_replacement_point_println(rp, 2); );
2142 /* replace_pop_native_frame ****************************************************
2144 Unroll a native frame in the execution state and create a source frame
2148 es...............current execution state
2149 ss...............the current source state
2150 sfi..............stackframeinfo for the native frame
2153 es...............execution state after unrolling the native frame
2154 ss...............gets the added native source frame
2156 *******************************************************************************/
2158 static void replace_pop_native_frame(executionstate_t *es,
2160 stackframeinfo *sfi)
2162 sourceframe_t *frame;
2168 frame = replace_new_sourceframe(ss);
2172 /* remember pc and size of native frame */
2174 frame->nativepc = es->pc;
2175 frame->nativeframesize = sfi->sp - es->sp;
2176 assert(frame->nativeframesize >= 0);
2178 /* remember values of saved registers */
2181 for (i=0; i<INT_REG_CNT; ++i) {
2182 if (nregdescint[i] == REG_SAV)
2183 frame->nativesavint[j++] = es->intregs[i];
2187 for (i=0; i<FLT_REG_CNT; ++i) {
2188 if (nregdescfloat[i] == REG_SAV)
2189 frame->nativesavflt[j++] = es->fltregs[i];
2192 #if defined(HAS_ADDRESS_REGISTER_FILE)
2194 for (i=0; i<ADR_REG_CNT; ++i) {
2195 if (nregdescadr[i] == REG_SAV)
2196 frame->nativesavadr[j++] = es->adrregs[i];
2200 /* restore saved registers */
2203 /* XXX we don't have them, yet, in the sfi, so clear them */
2205 for (i=0; i<INT_REG_CNT; ++i) {
2206 if (nregdescint[i] == REG_SAV)
2210 for (i=0; i<FLT_REG_CNT; ++i) {
2211 if (nregdescfloat[i] == REG_SAV)
2212 es->fltregs[i] = 0.0;
2215 # if defined(HAS_ADDRESS_REGISTER_FILE)
2216 for (i=0; i<ADR_REG_CNT; ++i) {
2217 if (nregdescadr[i] == REG_SAV)
2223 /* restore pv, pc, and sp */
2225 if (sfi->pv == NULL) {
2226 /* frame of a native function call */
2227 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2232 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2235 /* find the new codeinfo */
2237 DOLOG( printf("PV = %p\n", (void*) es->pv); );
2239 assert(es->pv != NULL);
2241 code = *(codeinfo **)(es->pv + CodeinfoPointer);
2243 DOLOG( printf("CODE = %p\n", (void*) code); );
2249 /* replace_push_native_frame ***************************************************
2251 Rebuild a native frame onto the execution state and remove its source frame.
2253 Note: The native frame is "rebuild" by setting fields like PC and stack
2254 pointer in the execution state accordingly. Values in the
2255 stackframeinfo may be modified, but the actual stack frame of the
2256 native code is not touched.
2259 es...............current execution state
2260 ss...............the current source state
2263 es...............execution state after re-rolling the native frame
2264 ss...............the native source frame is removed
2266 *******************************************************************************/
2268 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2270 sourceframe_t *frame;
2276 DOLOG( printf("pushing native frame\n"); );
2278 /* remove the frame from the source state */
2282 assert(REPLACE_IS_NATIVE_FRAME(frame));
2284 ss->frames = frame->down;
2286 /* assert that the native frame has not moved */
2288 assert(es->sp == frame->sfi->sp);
2290 /* restore saved registers */
2293 for (i=0; i<INT_REG_CNT; ++i) {
2294 if (nregdescint[i] == REG_SAV)
2295 es->intregs[i] = frame->nativesavint[j++];
2299 for (i=0; i<FLT_REG_CNT; ++i) {
2300 if (nregdescfloat[i] == REG_SAV)
2301 es->fltregs[i] = frame->nativesavflt[j++];
2304 #if defined(HAS_ADDRESS_REGISTER_FILE)
2306 for (i=0; i<ADR_REG_CNT; ++i) {
2307 if (nregdescadr[i] == REG_SAV)
2308 es->adrregs[i] = frame->nativesavadr[j++];
2312 /* skip the native frame on the machine stack */
2314 es->sp -= frame->nativeframesize;
2316 /* set the pc the next frame must return to */
2318 es->pc = frame->nativepc;
2322 /* replace_recover_source_state ************************************************
2324 Recover the source state from the given replacement point and execution
2328 rp...............replacement point that has been reached, if any
2329 sfi..............stackframeinfo, if called from native code
2330 es...............execution state at the replacement point rp
2335 *******************************************************************************/
2337 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2338 stackframeinfo *sfi,
2339 executionstate_t *es)
2344 #if defined(REPLACE_STATISTICS)
2348 /* create the source frame structure in dump memory */
2350 ss = DNEW(sourcestate_t);
2353 /* get the stackframeinfo if none is given */
2356 sfi = STACKFRAMEINFO;
2358 /* each iteration of the loop recovers one source frame */
2365 DOLOG( replace_executionstate_println(es); );
2367 /* if we are not at a replacement point, it is a native frame */
2370 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2373 replace_pop_native_frame(es, ss, sfi);
2376 if (es->code == NULL)
2379 goto after_machine_frame;
2382 /* read the values for this source frame from the execution state */
2384 DOLOG( printf("recovering source state for%s:\n",
2385 (ss->frames == NULL) ? " TOPFRAME" : "");
2386 replace_replacement_point_println(rp, 1); );
2388 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2390 #if defined(ENABLE_VMLOG)
2391 vmlog_cacao_unrol_method(ss->frames->method);
2394 #if defined(REPLACE_STATISTICS)
2395 REPLACE_COUNT(stat_frames);
2397 replace_statistics_source_frame(ss->frames);
2400 /* in locked areas (below native frames), identity map the frame */
2403 ss->frames->torp = ss->frames->fromrp;
2404 ss->frames->tocode = ss->frames->fromcode;
2407 /* unroll to the next (outer) frame */
2410 /* this frame is in inlined code */
2412 DOLOG( printf("INLINED!\n"); );
2416 assert(rp->type == RPLPOINT_TYPE_INLINE);
2417 REPLACE_COUNT(stat_unroll_inline);
2420 /* this frame had been called at machine-level. pop it. */
2422 DOLOG( printf("UNWIND\n"); );
2424 ra = replace_pop_activation_record(es, ss->frames);
2426 DOLOG( printf("REACHED NATIVE CODE\n"); );
2430 break; /* XXX remove to activate native frames */
2434 /* find the replacement point at the call site */
2436 after_machine_frame:
2437 rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2440 vm_abort("could not find replacement point while unrolling call");
2442 DOLOG( printf("found replacement point.\n");
2443 replace_replacement_point_println(rp, 1); );
2445 assert(rp->type == RPLPOINT_TYPE_CALL);
2446 REPLACE_COUNT(stat_unroll_call);
2448 } /* end loop over source frames */
2450 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2456 /* replace_map_source_state ****************************************************
2458 Map each source frame in the given source state to a target replacement
2459 point and compilation unit. If no valid code is available for a source
2460 frame, it is (re)compiled.
2463 ss...............the source state
2466 ss...............the source state, modified: The `torp` and `tocode`
2467 fields of each source frame are set.
2470 true.............everything went ok
2471 false............an exception has been thrown
2473 *******************************************************************************/
2475 static bool replace_map_source_state(sourcestate_t *ss)
2477 sourceframe_t *frame;
2480 rplpoint *parent; /* parent of inlined rplpoint */
2481 #if defined(REPLACE_STATISTICS)
2488 /* iterate over the source frames from outermost to innermost */
2490 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2492 /* XXX skip native frames */
2494 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2499 /* map frames which are not already mapped */
2501 if (frame->tocode) {
2502 code = frame->tocode;
2507 assert(frame->torp == NULL);
2509 if (parent == NULL) {
2510 /* find code for this frame */
2512 #if defined(REPLACE_STATISTICS)
2513 oldcode = frame->method->code;
2515 /* request optimization of hot methods and their callers */
2517 if (frame->method->hitcountdown < 0
2518 || (frame->down && frame->down->method->hitcountdown < 0))
2519 jit_request_optimization(frame->method);
2521 code = jit_get_current_code(frame->method);
2524 return false; /* exception */
2526 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2531 /* map this frame */
2533 rp = replace_find_replacement_point(code, frame, parent);
2535 frame->tocode = code;
2539 if (rp->type == RPLPOINT_TYPE_CALL) {
2552 /* replace_build_execution_state_intern ****************************************
2554 Build an execution state for the given (mapped) source state.
2556 !!! CAUTION: This function rewrites the machine stack !!!
2558 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2561 ss...............the source state. Must have been mapped by
2562 replace_map_source_state before.
2563 es...............the base execution state on which to build
2566 *es..............the new execution state
2568 *******************************************************************************/
2570 static void replace_build_execution_state_intern(sourcestate_t *ss,
2571 executionstate_t *es)
2574 sourceframe_t *prevframe;
2581 while (ss->frames) {
2583 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2584 prevframe = ss->frames;
2585 replace_push_native_frame(es, ss);
2591 if (parent == NULL) {
2592 /* create a machine-level stack frame */
2594 DOLOG( printf("pushing activation record for:\n");
2595 if (rp) replace_replacement_point_println(rp, 1);
2596 else printf("\tfirst frame\n"); );
2598 replace_push_activation_record(es, rp, prevframe, ss->frames);
2600 DOLOG( replace_executionstate_println(es); );
2603 rp = ss->frames->torp;
2606 DOLOG( printf("creating execution state for%s:\n",
2607 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2608 replace_replacement_point_println(ss->frames->fromrp, 1);
2609 replace_replacement_point_println(rp, 1); );
2611 es->code = ss->frames->tocode;
2612 prevframe = ss->frames;
2614 #if defined(ENABLE_VMLOG)
2615 vmlog_cacao_rerol_method(ss->frames->method);
2618 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2620 DOLOG( replace_executionstate_println(es); );
2622 if (rp->type == RPLPOINT_TYPE_CALL) {
2633 /* replace_build_execution_state ***********************************************
2635 This function contains the final phase of replacement. It builds the new
2636 execution state, releases dump memory, and returns to the calling
2637 assembler function which finishes replacement.
2639 NOTE: This function is called from asm_replacement_in, with the stack
2640 pointer at the start of the safe stack area.
2642 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2644 CAUTION: This function and its children must not use a lot of stack!
2645 There are only REPLACE_SAFESTACK_SIZE bytes of C stack
2649 st...............the safestack contained the necessary data
2651 *******************************************************************************/
2653 void replace_build_execution_state(replace_safestack_t *st)
2655 replace_build_execution_state_intern(st->ss, &(st->es));
2657 DOLOG( replace_executionstate_println(&(st->es)); );
2659 /* release dump area */
2661 dump_release(st->dumpsize);
2663 /* new code is entered after returning */
2665 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2669 /* replace_alloc_safestack *****************************************************
2671 Allocate a safe stack area to use during the final phase of replacement.
2672 The returned area is not initialized. This must be done by the caller.
2675 a newly allocated replace_safestack_t *
2677 *******************************************************************************/
2679 static replace_safestack_t *replace_alloc_safestack()
2682 replace_safestack_t *st;
2684 mem = MNEW(u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2686 st = (replace_safestack_t *) ((ptrint)(mem + REPLACE_STACK_ALIGNMENT - 1)
2687 & ~(REPLACE_STACK_ALIGNMENT - 1));
2689 #if !defined(NDEBUG)
2690 memset(st, 0xa5, sizeof(replace_safestack_t));
2699 /* replace_free_safestack ******************************************************
2701 Free the given safestack structure, making a copy of the contained
2702 execution state before freeing it.
2704 NOTE: This function is called from asm_replacement_in.
2707 st...............the safestack to free
2708 tmpes............where to copy the execution state to
2711 *tmpes...........receives a copy of st->es
2713 *******************************************************************************/
2715 void replace_free_safestack(replace_safestack_t *st, executionstate_t *tmpes)
2719 /* copy the executionstate_t to the temporary location */
2723 /* get the memory address to free */
2727 /* destroy memory (in debug mode) */
2729 #if !defined(NDEBUG)
2730 memset(st, 0xa5, sizeof(replace_safestack_t));
2733 /* free the safe stack struct */
2735 MFREE(mem, u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2739 /* replace_me_wrapper **********************************************************
2743 *******************************************************************************/
2745 bool replace_me_wrapper(u1 *pc)
2749 executionstate_t es;
2751 /* search the codeinfo for the given PC */
2753 code = code_find_codeinfo_for_pc(pc);
2756 /* search for a replacement point at the given PC */
2759 rp = replace_find_replacement_point_for_pc(code, pc);
2760 assert(rp == NULL || rp->pc == pc);
2766 for (i=0,rp2=code->rplpoints; i<code->rplpointcount; i++,rp2++) {
2773 /* check if the replacement point is active */
2775 if (rp != NULL && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
2777 /*md_replace_executionstate_read(&es, context);*/
2779 replace_me(rp, &es);
2788 /* replace_me ******************************************************************
2790 This function is called by asm_replacement_out when a thread reaches
2791 a replacement point. `replace_me` must map the execution state to the
2792 target replacement point and let execution continue there.
2794 This function never returns!
2797 rp...............replacement point that has been reached
2798 es...............execution state read by asm_replacement_out
2800 *******************************************************************************/
2802 void replace_me(rplpoint *rp, executionstate_t *es)
2805 sourceframe_t *frame;
2808 replace_safestack_t *safestack;
2811 es->code = code_find_codeinfo_for_pc(rp->pc);
2813 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2814 stat_replacements, (void*)THREADOBJECT,
2816 method_println(es->code->m); );
2818 DOLOG( replace_replacement_point_println(rp, 1);
2819 replace_executionstate_println(es); );
2821 REPLACE_COUNT(stat_replacements);
2823 /* mark start of dump memory area */
2825 dumpsize = dump_size();
2827 /* recover source state */
2829 ss = replace_recover_source_state(rp, NULL, es);
2831 /* map the source state */
2833 if (!replace_map_source_state(ss))
2834 vm_abort("exception during method replacement");
2836 DOLOG( replace_sourcestate_println(ss); );
2838 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2840 /* avoid infinite loops by self-replacement */
2844 frame = frame->down;
2846 if (frame->torp == origrp) {
2848 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2850 replace_deactivate_replacement_points(frame->tocode);
2853 /* write execution state of new code */
2855 DOLOG( replace_executionstate_println(es); );
2857 /* allocate a safe stack area and copy all needed data there */
2859 safestack = replace_alloc_safestack();
2861 safestack->es = *es;
2863 safestack->dumpsize = dumpsize;
2865 /* call the assembler code for the last phase of replacement */
2867 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
2868 /*asm_replacement_in(&(safestack->es), safestack);*/
2871 abort(); /* NOT REACHED */
2875 /******************************************************************************/
2876 /* NOTE: No important code below. */
2877 /******************************************************************************/
2880 /* statistics *****************************************************************/
2882 #if defined(REPLACE_STATISTICS)
2883 static void print_freq(FILE *file,int *array,int limit)
2888 for (i=0; i<limit; ++i)
2890 sum += array[limit];
2891 for (i=0; i<limit; ++i) {
2893 fprintf(file," %3d: %8d (cum %3d%%)\n",
2894 i, array[i], (sum) ? ((100*cum)/sum) : 0);
2896 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
2898 #endif /* defined(REPLACE_STATISTICS) */
2901 #if defined(REPLACE_STATISTICS)
2903 #define REPLACE_PRINT_DIST(name, array) \
2904 printf(" " name " distribution:\n"); \
2905 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
2907 void replace_print_statistics(void)
2909 printf("replacement statistics:\n");
2910 printf(" # of replacements: %d\n", stat_replacements);
2911 printf(" # of frames: %d\n", stat_frames);
2912 printf(" # of recompilations: %d\n", stat_recompile);
2913 printf(" patched static calls:%d\n", stat_staticpatch);
2914 printf(" unrolled inlines: %d\n", stat_unroll_inline);
2915 printf(" unrolled calls: %d\n", stat_unroll_call);
2916 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
2917 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
2918 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
2919 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
2920 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
2921 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
2922 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
2923 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
2924 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
2925 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
2927 printf(" # of methods: %d\n", stat_methods);
2928 printf(" # of replacement points: %d\n", stat_rploints);
2929 printf(" # of regallocs: %d\n", stat_regallocs);
2930 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
2931 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
2932 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
2936 #endif /* defined(REPLACE_STATISTICS) */
2939 #if defined(REPLACE_STATISTICS)
2940 static void replace_statistics_source_frame(sourceframe_t *frame)
2949 for (i=0; i<frame->javalocalcount; ++i) {
2950 switch (frame->javalocaltype[i]) {
2951 case TYPE_ADR: adr++; break;
2952 case TYPE_RET: ret++; break;
2953 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
2954 case TYPE_VOID: vd++; break;
2959 REPLACE_COUNT_DIST(stat_dist_locals, n);
2960 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
2961 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
2962 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
2963 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
2964 adr = ret = prim = n = 0;
2965 for (i=0; i<frame->javastackdepth; ++i) {
2966 switch (frame->javastacktype[i]) {
2967 case TYPE_ADR: adr++; break;
2968 case TYPE_RET: ret++; break;
2969 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
2973 REPLACE_COUNT_DIST(stat_dist_stack, n);
2974 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
2975 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
2976 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
2978 #endif /* defined(REPLACE_STATISTICS) */
2981 /* debugging helpers **********************************************************/
2983 /* replace_replacement_point_println *******************************************
2985 Print replacement point info.
2988 rp...............the replacement point to print
2990 *******************************************************************************/
2992 #if !defined(NDEBUG)
2994 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
2996 static char *replace_type_str[] = {
3006 void replace_replacement_point_println(rplpoint *rp, int depth)
3012 printf("(rplpoint *)NULL\n");
3016 for (j=0; j<depth; ++j)
3019 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3020 rp->id, (void*)rp,rp->pc,rp->callsize,
3021 replace_type_str[rp->type]);
3022 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3024 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3025 printf(" COUNTDOWN");
3026 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3028 printf(" parent:%p\n", (void*)rp->parent);
3029 for (j=0; j<depth; ++j)
3031 printf("ra:%d = [", rp->regalloccount);
3033 for (j=0; j<rp->regalloccount; ++j) {
3036 index = rp->regalloc[j].index;
3038 case RPLALLOC_STACK: printf("S"); break;
3039 case RPLALLOC_PARAM: printf("P"); break;
3040 case RPLALLOC_SYNC : printf("Y"); break;
3041 default: printf("%d", index);
3043 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3044 if (rp->regalloc[j].type == TYPE_RET) {
3045 printf("ret(L%03d)", rp->regalloc[j].regoff);
3048 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3053 for (j=0; j<depth; ++j)
3056 method_print(rp->method);
3060 #endif /* !defined(NDEBUG) */
3063 /* replace_show_replacement_points *********************************************
3065 Print replacement point info.
3068 code.............codeinfo whose replacement points should be printed.
3070 *******************************************************************************/
3072 #if !defined(NDEBUG)
3073 void replace_show_replacement_points(codeinfo *code)
3081 printf("(codeinfo *)NULL\n");
3085 printf("\treplacement points: %d\n",code->rplpointcount);
3087 printf("\ttotal allocations : %d\n",code->regalloccount);
3088 printf("\tsaved int regs : %d\n",code->savedintcount);
3089 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3090 #if defined(HAS_ADDRESS_REGISTER_FILE)
3091 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3093 printf("\tmemuse : %d\n",code->memuse);
3097 for (i=0; i<code->rplpointcount; ++i) {
3098 rp = code->rplpoints + i;
3101 parent = rp->parent;
3104 parent = parent->parent;
3106 replace_replacement_point_println(rp, depth);
3112 /* replace_executionstate_println **********************************************
3114 Print execution state
3117 es...............the execution state to print
3119 *******************************************************************************/
3121 #if !defined(NDEBUG)
3122 void replace_executionstate_println(executionstate_t *es)
3130 printf("(executionstate_t *)NULL\n");
3134 printf("executionstate_t:\n");
3135 printf("\tpc = %p",(void*)es->pc);
3136 printf(" sp = %p",(void*)es->sp);
3137 printf(" pv = %p\n",(void*)es->pv);
3138 #if defined(ENABLE_DISASSEMBLER)
3139 for (i=0; i<INT_REG_CNT; ++i) {
3144 #if SIZEOF_VOID_P == 8
3145 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3147 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3152 for (i=0; i<FLT_REG_CNT; ++i) {
3157 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3161 # if defined(HAS_ADDRESS_REGISTER_FILE)
3162 for (i=0; i<ADR_REG_CNT; ++i) {
3167 printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
3174 sp = (stackslot_t *) es->sp;
3179 methoddesc *md = es->code->m->parseddesc;
3180 slots = es->code->stackframesize;
3181 extraslots = 1 + md->memuse;
3188 printf("\tstack slots(+%d) at sp:", extraslots);
3189 for (i=0; i<slots+extraslots; ++i) {
3192 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3193 #ifdef HAS_4BYTE_STACKSLOT
3194 printf("%08lx",(unsigned long)*sp++);
3196 printf("%016llx",(unsigned long long)*sp++);
3198 printf("%c", (i >= slots) ? ')' : ' ');
3203 printf("\tcode: %p", (void*)es->code);
3204 if (es->code != NULL) {
3205 printf(" stackframesize=%d ", es->code->stackframesize);
3206 method_print(es->code->m);
3214 #if !defined(NDEBUG)
3215 static void java_value_print(s4 type, replace_val_t value)
3220 printf("%016llx",(unsigned long long) value.l);
3222 if (type < 0 || type > TYPE_RET)
3223 printf(" <INVALID TYPE:%d>", type);
3225 printf(" %s", show_jit_type_names[type]);
3227 if (type == TYPE_ADR && value.a != NULL) {
3230 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3232 if (obj->vftbl->class == class_java_lang_String) {
3234 u = javastring_toutf(obj, false);
3235 utf_display_printable_ascii(u);
3239 else if (type == TYPE_INT) {
3240 printf(" %ld", (long) value.i);
3242 else if (type == TYPE_LNG) {
3243 printf(" %lld", (long long) value.l);
3245 else if (type == TYPE_FLT) {
3246 printf(" %f", value.f);
3248 else if (type == TYPE_DBL) {
3249 printf(" %f", value.d);
3252 #endif /* !defined(NDEBUG) */
3255 #if !defined(NDEBUG)
3256 void replace_source_frame_println(sourceframe_t *frame)
3261 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3262 printf("\tNATIVE\n");
3263 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3264 printf("\tnativepc: %p\n", frame->nativepc);
3265 printf("\tframesize: %d\n", frame->nativeframesize);
3268 for (i=0; i<INT_REG_CNT; ++i) {
3269 if (nregdescint[i] == REG_SAV)
3270 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3274 for (i=0; i<FLT_REG_CNT; ++i) {
3275 if (nregdescfloat[i] == REG_SAV)
3276 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3284 method_println(frame->method);
3285 printf("\tid: %d\n", frame->id);
3286 printf("\ttype: %s\n", replace_type_str[frame->type]);
3289 if (frame->instance.a) {
3290 printf("\tinstance: ");
3291 java_value_print(TYPE_ADR, frame->instance);
3295 if (frame->javalocalcount) {
3296 printf("\tlocals (%d):\n",frame->javalocalcount);
3297 for (i=0; i<frame->javalocalcount; ++i) {
3298 t = frame->javalocaltype[i];
3299 if (t == TYPE_VOID) {
3300 printf("\tlocal[ %2d] = void\n",i);
3303 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3304 java_value_print(t, frame->javalocals[i]);
3311 if (frame->javastackdepth) {
3312 printf("\tstack (depth %d):\n",frame->javastackdepth);
3313 for (i=0; i<frame->javastackdepth; ++i) {
3314 t = frame->javastacktype[i];
3315 if (t == TYPE_VOID) {
3316 printf("\tstack[%2d] = void", i);
3319 printf("\tstack[%2d] = ",i);
3320 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3327 if (frame->syncslotcount) {
3328 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3329 for (i=0; i<frame->syncslotcount; ++i) {
3330 printf("\tslot[%2d] = ",i);
3331 #ifdef HAS_4BYTE_STACKSLOT
3332 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3334 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3340 if (frame->fromcode) {
3341 printf("\tfrom %p ", (void*)frame->fromcode);
3342 method_println(frame->fromcode->m);
3344 if (frame->tocode) {
3345 printf("\tto %p ", (void*)frame->tocode);
3346 method_println(frame->tocode->m);
3349 if (frame->fromrp) {
3350 printf("\tfrom replacement point:\n");
3351 replace_replacement_point_println(frame->fromrp, 2);
3354 printf("\tto replacement point:\n");
3355 replace_replacement_point_println(frame->torp, 2);
3360 #endif /* !defined(NDEBUG) */
3363 /* replace_sourcestate_println *************************************************
3368 ss...............the source state to print
3370 *******************************************************************************/
3372 #if !defined(NDEBUG)
3373 void replace_sourcestate_println(sourcestate_t *ss)
3376 sourceframe_t *frame;
3379 printf("(sourcestate_t *)NULL\n");
3383 printf("sourcestate_t:\n");
3385 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3386 printf(" frame %d:\n", i);
3387 replace_source_frame_println(frame);
3393 /* replace_sourcestate_println_short *******************************************
3395 Print a compact representation of the given source state.
3398 ss...............the source state to print
3400 *******************************************************************************/
3402 #if !defined(NDEBUG)
3403 void replace_sourcestate_println_short(sourcestate_t *ss)
3405 sourceframe_t *frame;
3407 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3410 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3411 printf("NATIVE (pc %p size %d) ",
3412 (void*)frame->nativepc, frame->nativeframesize);
3413 replace_stackframeinfo_println(frame->sfi);
3418 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3421 printf("%s", replace_type_str[frame->fromrp->type]);
3423 if (frame->torp && frame->torp->type != frame->fromrp->type)
3424 printf("->%s", replace_type_str[frame->torp->type]);
3426 if (frame->tocode != frame->fromcode)
3427 printf(" (%p->%p/%d) ",
3428 (void*) frame->fromcode, (void*) frame->tocode,
3431 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3433 method_println(frame->method);
3438 #if !defined(NDEBUG)
3439 static void replace_stackframeinfo_println(stackframeinfo *sfi)
3441 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3442 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3443 (void*)sfi->ra, (void*)sfi->xpc);
3446 method_println(sfi->method);
3453 * These are local overrides for various environment variables in Emacs.
3454 * Please do not remove this and leave it at the end of the file, where
3455 * Emacs will automagically detect them.
3456 * ---------------------------------------------------------------------
3459 * indent-tabs-mode: t
3463 * vim:noexpandtab:sw=4:ts=4: