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 #if defined(ENABLE_GC_CACAO)
38 # include "mm/cacao-gc/gc.h"
41 #include "mm/memory.h"
43 #include "threads/threads-common.h"
45 #include "toolbox/logging.h"
47 #include "vm/stringlocal.h"
49 #include "vm/jit/abi.h"
50 #include "vm/jit/asmpart.h"
51 #include "vm/jit/disass.h"
52 #include "vm/jit/jit.h"
53 #include "vm/jit/md.h"
54 #include "vm/jit/methodheader.h"
55 #include "vm/jit/replace.h"
56 #include "vm/jit/show.h"
57 #include "vm/jit/stack.h"
59 #include "vmcore/options.h"
60 #include "vmcore/classcache.h"
63 #define REPLACE_PATCH_DYNAMIC_CALL
64 /*#define REPLACE_PATCH_ALL*/
66 #if defined(ENABLE_VMLOG)
67 #include <vmlog_cacao.h>
70 /*** architecture-dependent configuration *************************************/
72 /* first unset the macros (default) */
73 #undef REPLACE_RA_BETWEEN_FRAMES
74 #undef REPLACE_RA_TOP_OF_FRAME
75 #undef REPLACE_RA_LINKAGE_AREA
76 #undef REPLACE_LEAFMETHODS_RA_REGISTER
80 #if defined(__I386__) || defined(__X86_64__)
81 #define REPLACE_RA_BETWEEN_FRAMES
83 #elif defined(__ALPHA__)
84 #define REPLACE_RA_TOP_OF_FRAME
85 #define REPLACE_LEAFMETHODS_RA_REGISTER
86 #define REPLACE_REG_RA REG_RA
88 #elif defined(__POWERPC__)
89 #define REPLACE_RA_LINKAGE_AREA
90 #define REPLACE_LEAFMETHODS_RA_REGISTER
91 #define REPLACE_REG_RA REG_ITMP3 /* the execution state has the LR in 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 ****************************************************************/
112 /*#define REPLACE_VERBOSE*/
115 static void java_value_print(s4 type, replace_val_t value);
116 static void replace_stackframeinfo_println(stackframeinfo *sfi);
119 #if !defined(NDEBUG) && defined(REPLACE_VERBOSE)
120 int replace_verbose = 0;
121 #define DOLOG(code) do{ if (replace_verbose > 1) { code; } } while(0)
122 #define DOLOG_SHORT(code) do{ if (replace_verbose > 0) { code; } } while(0)
125 #define DOLOG_SHORT(code)
129 /*** statistics ***************************************************************/
131 #define REPLACE_STATISTICS
133 #if defined(REPLACE_STATISTICS)
135 static int stat_replacements = 0;
136 static int stat_frames = 0;
137 static int stat_recompile = 0;
138 static int stat_staticpatch = 0;
139 static int stat_unroll_inline = 0;
140 static int stat_unroll_call = 0;
141 static int stat_dist_frames[20] = { 0 };
142 static int stat_dist_locals[20] = { 0 };
143 static int stat_dist_locals_adr[10] = { 0 };
144 static int stat_dist_locals_prim[10] = { 0 };
145 static int stat_dist_locals_ret[10] = { 0 };
146 static int stat_dist_locals_void[10] = { 0 };
147 static int stat_dist_stack[10] = { 0 };
148 static int stat_dist_stack_adr[10] = { 0 };
149 static int stat_dist_stack_prim[10] = { 0 };
150 static int stat_dist_stack_ret[10] = { 0 };
151 static int stat_methods = 0;
152 static int stat_rploints = 0;
153 static int stat_regallocs = 0;
154 static int stat_dist_method_rplpoints[20] = { 0 };
156 #define REPLACE_COUNT(cnt) (cnt)++
157 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
158 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
160 #define REPLACE_COUNT_DIST(array, val) \
162 int limit = (sizeof(array) / sizeof(int)) - 1; \
163 if ((val) < (limit)) (array)[val]++; \
164 else (array)[limit]++; \
167 static void replace_statistics_source_frame(sourceframe_t *frame);
171 #define REPLACE_COUNT(cnt)
172 #define REPLACE_COUNT_IF(cnt, cond)
173 #define REPLACE_COUNT_INC(cnt, inc)
174 #define REPLACE_COUNT_DIST(array, val)
176 #endif /* defined(REPLACE_STATISTICS) */
179 /*** constants used internally ************************************************/
181 #define TOP_IS_NORMAL 0
182 #define TOP_IS_ON_STACK 1
183 #define TOP_IS_IN_ITMP1 2
184 #define TOP_IS_VOID 3
187 /******************************************************************************/
188 /* PART I: Creating / freeing replacement points */
189 /******************************************************************************/
192 /* replace_create_replacement_point ********************************************
194 Create a replacement point.
197 jd...............current jitdata
198 iinfo............inlining info for the current position
199 rp...............pre-allocated (uninitialized) rplpoint
200 type.............RPLPOINT_TYPE constant
201 iptr.............current instruction
202 *pra.............current rplalloc pointer
203 javalocals.......the javalocals at the current point
204 stackvars........the stack variables at the current point
205 stackdepth.......the stack depth at the current point
206 paramcount.......number of parameters at the start of stackvars
209 *rpa.............points to the next free rplalloc
211 *******************************************************************************/
213 static void replace_create_replacement_point(jitdata *jd,
214 insinfo_inline *iinfo,
231 REPLACE_COUNT(stat_rploints);
233 rp->method = (iinfo) ? iinfo->method : jd->m;
234 rp->pc = NULL; /* set by codegen */
235 rp->callsize = 0; /* set by codegen */
239 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
241 /* XXX unify these two fields */
242 rp->parent = (iinfo) ? iinfo->rp : NULL;
244 /* store local allocation info of javalocals */
247 for (i = 0; i < rp->method->maxlocals; ++i) {
248 index = javalocals[i];
255 ra->flags = v->flags & (INMEMORY);
256 ra->regoff = v->vv.regoff;
260 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
268 /* store allocation info of java stack vars */
270 for (i = 0; i < stackdepth; ++i) {
271 v = VAR(stackvars[i]);
272 ra->flags = v->flags & (INMEMORY);
273 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
275 /* XXX how to handle locals on the stack containing returnAddresses? */
276 if (v->type == TYPE_RET) {
277 assert(stackvars[i] >= jd->localcount);
278 ra->regoff = v->vv.retaddr->nr;
281 ra->regoff = v->vv.regoff;
285 /* total number of allocations */
287 rp->regalloccount = ra - rp->regalloc;
293 /* replace_create_inline_start_replacement_point *******************************
295 Create an INLINE_START replacement point.
298 jd...............current jitdata
299 rp...............pre-allocated (uninitialized) rplpoint
300 iptr.............current instruction
301 *pra.............current rplalloc pointer
302 javalocals.......the javalocals at the current point
305 *rpa.............points to the next free rplalloc
308 the insinfo_inline * for the following inlined body
310 *******************************************************************************/
312 static insinfo_inline * replace_create_inline_start_replacement_point(
319 insinfo_inline *calleeinfo;
322 calleeinfo = iptr->sx.s23.s3.inlineinfo;
326 replace_create_replacement_point(jd, calleeinfo->parent, rp,
327 RPLPOINT_TYPE_INLINE, iptr, pra,
329 calleeinfo->stackvars, calleeinfo->stackvarscount,
330 calleeinfo->paramcount);
332 if (calleeinfo->synclocal != UNUSED) {
334 ra->index = RPLALLOC_SYNC;
335 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
336 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
346 /* replace_create_replacement_points *******************************************
348 Create the replacement points for the given code.
351 jd...............current jitdata, must not have any replacement points
354 code->rplpoints.......set to the list of replacement points
355 code->rplpointcount...number of replacement points
356 code->regalloc........list of allocation info
357 code->regalloccount...total length of allocation info list
358 code->globalcount.....number of global allocations at the
359 start of code->regalloc
362 true.............everything ok
363 false............an exception has been thrown
365 *******************************************************************************/
367 #define CLEAR_javalocals(array, method) \
369 for (i=0; i<(method)->maxlocals; ++i) \
370 (array)[i] = UNUSED; \
373 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
375 if ((array) != NULL) \
376 MCOPY((dest), (array), s4, (method)->maxlocals); \
378 CLEAR_javalocals((dest), (method)); \
381 #define COUNT_javalocals(array, method, counter) \
383 for (i=0; i<(method)->maxlocals; ++i) \
384 if ((array)[i] != UNUSED) \
388 bool replace_create_replacement_points(jitdata *jd)
406 insinfo_inline *iinfo;
409 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
413 REPLACE_COUNT(stat_methods);
415 /* get required compiler data */
420 /* assert that we wont overwrite already allocated data */
424 assert(code->rplpoints == NULL);
425 assert(code->rplpointcount == 0);
426 assert(code->regalloc == NULL);
427 assert(code->regalloccount == 0);
428 assert(code->globalcount == 0);
432 /* set codeinfo flags */
434 if (jd->isleafmethod)
435 CODE_SETFLAG_LEAFMETHOD(code);
437 /* in instance methods, we may need a rplpoint at the method entry */
439 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
440 if (!(m->flags & ACC_STATIC)) {
441 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
447 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
449 /* iterate over the basic block list to find replacement points */
454 javalocals = DMNEW(s4, jd->maxlocals);
456 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
460 if (bptr->flags < BBFINISHED)
463 /* get info about this block */
466 iinfo = bptr->inlineinfo;
468 /* initialize javalocals at the start of this block */
470 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
472 /* iterate over the instructions */
475 iend = iptr + bptr->icount;
479 for (; iptr != iend; ++iptr) {
481 case ICMD_INVOKESTATIC:
482 case ICMD_INVOKESPECIAL:
483 case ICMD_INVOKEVIRTUAL:
484 case ICMD_INVOKEINTERFACE:
485 INSTRUCTION_GET_METHODDESC(iptr, md);
487 COUNT_javalocals(javalocals, m, alloccount);
488 alloccount += iptr->s1.argcount;
490 alloccount -= iinfo->throughcount;
498 stack_javalocals_store(iptr, javalocals);
512 case ICMD_INLINE_START:
513 iinfo = iptr->sx.s23.s3.inlineinfo;
516 COUNT_javalocals(javalocals, m, alloccount);
517 alloccount += iinfo->stackvarscount;
518 if (iinfo->synclocal != UNUSED)
522 /* javalocals may be set at next block start, or now */
523 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
526 case ICMD_INLINE_BODY:
527 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
529 jl = iinfo->javalocals_start;
531 /* get the javalocals from the following block start */
533 jl = bptr->next->javalocals;
536 COUNT_javalocals(jl, m, alloccount);
539 case ICMD_INLINE_END:
540 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
541 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
542 iinfo = iptr->sx.s23.s3.inlineinfo;
544 if (iinfo->javalocals_end)
545 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
546 iinfo = iinfo->parent;
550 if (iptr == bptr->iinstr)
552 } /* end instruction loop */
554 /* create replacement points at targets of backward branches */
555 /* We only need the replacement point there, if there is no */
556 /* replacement point inside the block. */
558 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
559 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
560 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
564 if (test > startcount) {
565 /* we don't need an extra rplpoint */
566 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
570 alloccount += bptr->indepth;
571 if (bptr->inlineinfo)
572 alloccount -= bptr->inlineinfo->throughcount;
574 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
578 } /* end basicblock loop */
580 /* if no points were found, there's nothing to do */
585 /* allocate replacement point array and allocation array */
587 rplpoints = MNEW(rplpoint, count);
588 regalloc = MNEW(rplalloc, alloccount);
591 /* initialize replacement point structs */
595 /* XXX try to share code with the counting loop! */
597 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
600 if (bptr->flags < BBFINISHED)
603 /* get info about this block */
606 iinfo = bptr->inlineinfo;
608 /* initialize javalocals at the start of this block */
610 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
612 /* create replacement points at targets of backward branches */
614 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
616 i = (iinfo) ? iinfo->throughcount : 0;
617 replace_create_replacement_point(jd, iinfo, rp++,
618 bptr->type, bptr->iinstr, &ra,
619 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
621 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
622 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
625 /* iterate over the instructions */
628 iend = iptr + bptr->icount;
630 for (; iptr != iend; ++iptr) {
632 case ICMD_INVOKESTATIC:
633 case ICMD_INVOKESPECIAL:
634 case ICMD_INVOKEVIRTUAL:
635 case ICMD_INVOKEINTERFACE:
636 INSTRUCTION_GET_METHODDESC(iptr, md);
638 i = (iinfo) ? iinfo->throughcount : 0;
639 replace_create_replacement_point(jd, iinfo, rp++,
640 RPLPOINT_TYPE_CALL, iptr, &ra,
641 javalocals, iptr->sx.s23.s2.args,
642 iptr->s1.argcount - i,
651 stack_javalocals_store(iptr, javalocals);
659 replace_create_replacement_point(jd, iinfo, rp++,
660 RPLPOINT_TYPE_RETURN, iptr, &ra,
661 NULL, &(iptr->s1.varindex), 1, 0);
665 replace_create_replacement_point(jd, iinfo, rp++,
666 RPLPOINT_TYPE_RETURN, iptr, &ra,
670 case ICMD_INLINE_START:
671 iinfo = replace_create_inline_start_replacement_point(
672 jd, rp++, iptr, &ra, javalocals);
674 /* javalocals may be set at next block start, or now */
675 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
678 case ICMD_INLINE_BODY:
679 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
681 jl = iinfo->javalocals_start;
683 /* get the javalocals from the following block start */
685 jl = bptr->next->javalocals;
687 /* create a non-trappable rplpoint */
688 replace_create_replacement_point(jd, iinfo, rp++,
689 RPLPOINT_TYPE_BODY, iptr, &ra,
691 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
694 case ICMD_INLINE_END:
695 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
696 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
697 iinfo = iptr->sx.s23.s3.inlineinfo;
699 if (iinfo->javalocals_end)
700 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
701 iinfo = iinfo->parent;
704 } /* end instruction loop */
705 } /* end basicblock loop */
707 assert((rp - rplpoints) == count);
708 assert((ra - regalloc) == alloccount);
710 /* store the data in the codeinfo */
712 code->rplpoints = rplpoints;
713 code->rplpointcount = count;
714 code->regalloc = regalloc;
715 code->regalloccount = alloccount;
716 code->globalcount = 0;
717 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
718 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
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(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(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 sp...............stack pointer of the execution state (XXX eliminate?)
924 ra...............allocation
925 javaval..........where to put the value
928 *javaval.........the value
930 *******************************************************************************/
932 static void replace_read_value(executionstate_t *es,
935 replace_val_t *javaval)
937 if (ra->flags & INMEMORY) {
938 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
939 #ifdef HAS_4BYTE_STACKSLOT
940 if (IS_2_WORD_TYPE(ra->type)) {
941 javaval->l = *(u8*)(sp + ra->regoff);
945 javaval->p = sp[ra->regoff];
946 #ifdef HAS_4BYTE_STACKSLOT
951 /* allocated register */
952 if (IS_FLT_DBL_TYPE(ra->type)) {
953 javaval->d = es->fltregs[ra->regoff];
955 if (ra->type == TYPE_FLT)
956 javaval->f = javaval->d;
959 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
960 if (ra->type == TYPE_LNG) {
961 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
962 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
965 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
966 javaval->p = es->intregs[ra->regoff];
972 /* replace_write_value *********************************************************
974 Write a value to the given allocation in the execution state.
977 es...............execution state
978 sp...............stack pointer of the execution state (XXX eliminate?)
979 ra...............allocation
980 *javaval.........the value
982 *******************************************************************************/
984 static void replace_write_value(executionstate_t *es,
987 replace_val_t *javaval)
989 if (ra->flags & INMEMORY) {
990 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
991 #ifdef HAS_4BYTE_STACKSLOT
992 if (IS_2_WORD_TYPE(ra->type)) {
993 *(u8*)(sp + ra->regoff) = javaval->l;
997 sp[ra->regoff] = javaval->p;
998 #ifdef HAS_4BYTE_STACKSLOT
1003 /* allocated register */
1006 es->fltregs[ra->regoff] = (double) javaval->f;
1009 es->fltregs[ra->regoff] = javaval->d;
1011 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1013 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1014 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1018 es->intregs[ra->regoff] = javaval->p;
1024 /* replace_read_executionstate *************************************************
1026 Read the given executions state and translate it to a source frame.
1029 ss...............the source state
1032 ss->frames.......set to new frame
1035 returns the new frame
1037 *******************************************************************************/
1039 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1041 sourceframe_t *frame;
1043 frame = DNEW(sourceframe_t);
1044 MZERO(frame, sourceframe_t, 1);
1046 frame->down = ss->frames;
1053 /* replace_read_executionstate *************************************************
1055 Read the given executions state and translate it to a source frame.
1058 rp...............replacement point at which `es` was taken
1059 es...............execution state
1060 ss...............where to put the source state
1063 *ss..............the source state derived from the execution state
1065 *******************************************************************************/
1067 static s4 replace_normalize_type_map[] = {
1068 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1069 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1070 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1071 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1072 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1073 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1074 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1078 static void replace_read_executionstate(rplpoint *rp,
1079 executionstate_t *es,
1088 sourceframe_t *frame;
1091 stackslot_t *basesp;
1093 code = code_find_codeinfo_for_pc(rp->pc);
1095 topslot = TOP_IS_NORMAL;
1099 sp = (stackslot_t *) es->sp;
1101 /* in some cases the top stack slot is passed in REG_ITMP1 */
1103 if (rp->type == BBTYPE_EXH) {
1104 topslot = TOP_IS_IN_ITMP1;
1107 /* calculate base stack pointer */
1109 basesp = sp + code_get_stack_frame_size(code);
1111 /* create the source frame */
1113 frame = replace_new_sourceframe(ss);
1114 frame->method = rp->method;
1116 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1117 frame->type = replace_normalize_type_map[rp->type];
1119 frame->fromcode = code;
1121 /* read local variables */
1123 count = m->maxlocals;
1124 frame->javalocalcount = count;
1125 frame->javalocals = DMNEW(replace_val_t, count);
1126 frame->javalocaltype = DMNEW(u1, count);
1128 /* mark values as undefined */
1129 for (i=0; i<count; ++i) {
1130 #if !defined(NDEBUG)
1131 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1133 frame->javalocaltype[i] = TYPE_VOID;
1136 /* some entries in the intregs array are not meaningful */
1137 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1138 #if !defined(NDEBUG)
1139 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1141 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1143 #endif /* !defined(NDEBUG) */
1145 /* read javalocals */
1147 count = rp->regalloccount;
1150 while (count && (i = ra->index) >= 0) {
1151 assert(i < m->maxlocals);
1152 frame->javalocaltype[i] = ra->type;
1153 if (ra->type == TYPE_RET)
1154 frame->javalocals[i].i = ra->regoff;
1156 replace_read_value(es, sp, ra, frame->javalocals + i);
1161 /* read instance, if this is the first rplpoint */
1163 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1164 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1166 /* we are at the start of the method body, so if local 0 is set, */
1167 /* it is the instance. */
1168 if (frame->javalocaltype[0] == TYPE_ADR)
1169 frame->instance = frame->javalocals[0];
1174 md = rp->method->parseddesc;
1176 assert(md->paramcount >= 1);
1177 instra.type = TYPE_ADR;
1178 instra.regoff = md->params[0].regoff;
1179 if (md->params[0].inmemory) {
1180 instra.flags = INMEMORY;
1181 instra.regoff += (1 + code->stackframesize);
1186 replace_read_value(es, sp, &instra, &(frame->instance));
1189 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1191 /* read stack slots */
1193 frame->javastackdepth = count;
1194 frame->javastack = DMNEW(replace_val_t, count);
1195 frame->javastacktype = DMNEW(u1, count);
1197 #if !defined(NDEBUG)
1198 /* mark values as undefined */
1199 for (i=0; i<count; ++i) {
1200 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1201 frame->javastacktype[i] = TYPE_VOID;
1203 #endif /* !defined(NDEBUG) */
1207 /* the first stack slot is special in SBR and EXH blocks */
1209 if (topslot == TOP_IS_ON_STACK) {
1212 assert(ra->index == RPLALLOC_STACK);
1213 assert(ra->type == TYPE_ADR);
1214 frame->javastack[i].p = sp[-1];
1215 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1220 else if (topslot == TOP_IS_IN_ITMP1) {
1223 assert(ra->index == RPLALLOC_STACK);
1224 assert(ra->type == TYPE_ADR);
1225 frame->javastack[i].p = es->intregs[REG_ITMP1];
1226 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1231 else if (topslot == TOP_IS_VOID) {
1234 assert(ra->index == RPLALLOC_STACK);
1235 frame->javastack[i].l = 0;
1236 frame->javastacktype[i] = TYPE_VOID;
1242 /* read remaining stack slots */
1244 for (; count--; ra++) {
1245 if (ra->index == RPLALLOC_SYNC) {
1246 assert(rp->type == RPLPOINT_TYPE_INLINE);
1248 /* only read synchronization slots when traversing an inline point */
1251 sourceframe_t *calleeframe = frame->down;
1252 assert(calleeframe);
1253 assert(calleeframe->syncslotcount == 0);
1254 assert(calleeframe->syncslots == NULL);
1256 calleeframe->syncslotcount = 1;
1257 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1258 replace_read_value(es,sp,ra,calleeframe->syncslots);
1261 frame->javastackdepth--;
1265 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1267 /* do not read parameters of calls down the call chain */
1269 if (!topframe && ra->index == RPLALLOC_PARAM) {
1270 frame->javastackdepth--;
1273 if (ra->type == TYPE_RET)
1274 frame->javastack[i].i = ra->regoff;
1276 replace_read_value(es,sp,ra,frame->javastack + i);
1277 frame->javastacktype[i] = ra->type;
1284 /* replace_write_executionstate ************************************************
1286 Translate the given source state into an execution state.
1289 rp...............replacement point for which execution state should be
1291 es...............where to put the execution state
1292 ss...............the given source state
1295 *es..............the execution state derived from the source state
1297 *******************************************************************************/
1299 static void replace_write_executionstate(rplpoint *rp,
1300 executionstate_t *es,
1309 sourceframe_t *frame;
1312 stackslot_t *basesp;
1314 code = code_find_codeinfo_for_pc(rp->pc);
1316 topslot = TOP_IS_NORMAL;
1318 /* pop a source frame */
1322 ss->frames = frame->down;
1324 /* calculate stack pointer */
1326 sp = (stackslot_t *) es->sp;
1328 basesp = sp + code_get_stack_frame_size(code);
1330 /* in some cases the top stack slot is passed in REG_ITMP1 */
1332 if (rp->type == BBTYPE_EXH) {
1333 topslot = TOP_IS_IN_ITMP1;
1336 /* write javalocals */
1339 count = rp->regalloccount;
1341 while (count && (i = ra->index) >= 0) {
1342 assert(i < m->maxlocals);
1343 assert(i < frame->javalocalcount);
1344 assert(ra->type == frame->javalocaltype[i]);
1345 if (ra->type == TYPE_RET) {
1346 /* XXX assert that it matches this rplpoint */
1349 replace_write_value(es, sp, ra, frame->javalocals + i);
1354 /* write stack slots */
1358 /* the first stack slot is special in SBR and EXH blocks */
1360 if (topslot == TOP_IS_ON_STACK) {
1363 assert(ra->index == RPLALLOC_STACK);
1364 assert(i < frame->javastackdepth);
1365 assert(frame->javastacktype[i] == TYPE_ADR);
1366 sp[-1] = frame->javastack[i].p;
1371 else if (topslot == TOP_IS_IN_ITMP1) {
1374 assert(ra->index == RPLALLOC_STACK);
1375 assert(i < frame->javastackdepth);
1376 assert(frame->javastacktype[i] == TYPE_ADR);
1377 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1382 else if (topslot == TOP_IS_VOID) {
1385 assert(ra->index == RPLALLOC_STACK);
1386 assert(i < frame->javastackdepth);
1387 assert(frame->javastacktype[i] == TYPE_VOID);
1393 /* write remaining stack slots */
1395 for (; count--; ra++) {
1396 if (ra->index == RPLALLOC_SYNC) {
1397 assert(rp->type == RPLPOINT_TYPE_INLINE);
1399 /* only write synchronization slots when traversing an inline point */
1402 assert(frame->down);
1403 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1404 assert(frame->down->syncslots != NULL);
1406 replace_write_value(es,sp,ra,frame->down->syncslots);
1411 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1413 /* do not write parameters of calls down the call chain */
1415 if (!topframe && ra->index == RPLALLOC_PARAM) {
1419 assert(i < frame->javastackdepth);
1420 assert(ra->type == frame->javastacktype[i]);
1421 if (ra->type == TYPE_RET) {
1422 /* XXX assert that it matches this rplpoint */
1425 replace_write_value(es,sp,ra,frame->javastack + i);
1437 /* replace_pop_activation_record ***********************************************
1439 Peel a stack frame from the execution state.
1441 *** This function imitates the effects of the method epilog ***
1442 *** and returning from the method call. ***
1445 es...............execution state
1446 frame............source frame, receives synchronization slots
1449 *es..............the execution state after popping the stack frame
1451 *******************************************************************************/
1453 u1* replace_pop_activation_record(executionstate_t *es,
1454 sourceframe_t *frame)
1462 stackslot_t *basesp;
1468 /* read the return address */
1470 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1471 if (CODE_IS_LEAFMETHOD(es->code))
1472 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1475 ra = md_stacktrace_get_returnaddress(es->sp,
1476 SIZE_OF_STACKSLOT * es->code->stackframesize);
1478 DOLOG( printf("return address: %p\n", (void*)ra); );
1482 /* calculate the base of the stack frame */
1484 sp = (stackslot_t *) es->sp;
1485 basesp = sp + es->code->stackframesize;
1487 /* read slots used for synchronization */
1489 assert(frame->syncslotcount == 0);
1490 assert(frame->syncslots == NULL);
1491 count = code_get_sync_slot_count(es->code);
1492 frame->syncslotcount = count;
1493 frame->syncslots = DMNEW(replace_val_t, count);
1494 for (i=0; i<count; ++i) {
1495 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1498 /* restore return address, if part of frame */
1500 #if defined(REPLACE_RA_TOP_OF_FRAME)
1501 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1502 if (!CODE_IS_LEAFMETHOD(es->code))
1504 es->intregs[REPLACE_REG_RA] = *--basesp;
1505 #endif /* REPLACE_RA_TOP_OF_FRAME */
1507 #if defined(REPLACE_RA_LINKAGE_AREA)
1508 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1509 if (!CODE_IS_LEAFMETHOD(es->code))
1511 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1512 #endif /* REPLACE_RA_LINKAGE_AREA */
1514 /* restore saved int registers */
1517 for (i=0; i<es->code->savedintcount; ++i) {
1518 while (nregdescint[--reg] != REG_SAV)
1520 es->intregs[reg] = *--basesp;
1523 /* restore saved flt registers */
1527 for (i=0; i<es->code->savedfltcount; ++i) {
1528 while (nregdescfloat[--reg] != REG_SAV)
1530 basesp -= STACK_SLOTS_PER_FLOAT;
1531 es->fltregs[reg] = *(double*)basesp;
1534 /* adjust the stackpointer */
1536 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1538 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1539 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1542 /* Set the new pc. Subtract one so we do not hit the replacement point */
1543 /* of the instruction following the call, if there is one. */
1547 /* find the new codeinfo */
1549 pv = md_codegen_get_pv_from_pc(ra);
1551 DOLOG( printf("PV = %p\n", (void*) pv); );
1553 if (pv == NULL) /* XXX can this really happen? */
1556 code = *(codeinfo **)(pv + CodeinfoPointer);
1558 DOLOG( printf("CODE = %p\n", (void*) code); );
1560 /* return NULL if we reached native code */
1565 /* in debugging mode clobber non-saved registers */
1567 #if !defined(NDEBUG)
1569 for (i=0; i<INT_REG_CNT; ++i)
1570 if ((nregdescint[i] != REG_SAV)
1572 && (i != REPLACE_REG_RA)
1575 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1576 for (i=0; i<FLT_REG_CNT; ++i)
1577 if (nregdescfloat[i] != REG_SAV)
1578 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1579 #endif /* !defined(NDEBUG) */
1581 return (code) ? ra : NULL;
1585 /* replace_patch_method_pointer ************************************************
1587 Patch a method pointer (may be in code, data segment, vftbl, or interface
1591 mpp..............address of the method pointer to patch
1592 entrypoint.......the new entrypoint of the method
1593 kind.............kind of call to patch, used only for debugging
1595 *******************************************************************************/
1597 static void replace_patch_method_pointer(methodptr *mpp,
1598 methodptr entrypoint,
1601 #if !defined(NDEBUG)
1606 DOLOG( printf("patch method pointer from: %p to %p\n",
1607 (void*) *mpp, (void*)entrypoint); );
1609 #if !defined(NDEBUG)
1610 oldcode = *(codeinfo **)((u1*)(*mpp) + CodeinfoPointer);
1611 newcode = *(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer);
1613 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1614 method_println(oldcode->m);
1615 printf("\t with %p ", (void*) newcode);
1616 method_println(newcode->m); );
1618 assert(oldcode->m == newcode->m);
1621 /* write the new entrypoint */
1623 *mpp = (methodptr) entrypoint;
1627 /* replace_patch_class *********************************************************
1629 Patch a method in the given class.
1632 vftbl............vftbl of the class
1633 m................the method to patch
1634 oldentrypoint....the old entrypoint to replace
1635 entrypoint.......the new entrypoint
1637 *******************************************************************************/
1639 void replace_patch_class(vftbl_t *vftbl,
1648 /* patch the vftbl of the class */
1650 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1654 /* patch the interface tables */
1656 assert(oldentrypoint);
1658 for (i=0; i < vftbl->interfacetablelength; ++i) {
1659 mpp = vftbl->interfacetable[-i];
1660 mppend = mpp + vftbl->interfacevftbllength[i];
1661 for (; mpp != mppend; ++mpp)
1662 if (*mpp == oldentrypoint) {
1663 replace_patch_method_pointer(mpp, entrypoint, "interface");
1669 /* replace_patch_class_hierarchy ***********************************************
1671 Patch a method in all loaded classes.
1674 m................the method to patch
1675 oldentrypoint....the old entrypoint to replace
1676 entrypoint.......the new entrypoint
1678 *******************************************************************************/
1680 struct replace_patch_data_t {
1686 #define CODEINFO_OF_CODE(entrypoint) \
1687 (*(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer))
1689 #define METHOD_OF_CODE(entrypoint) \
1690 (CODEINFO_OF_CODE(entrypoint)->m)
1692 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1694 vftbl_t *vftbl = c->vftbl;
1697 && vftbl->vftbllength > pd->m->vftblindex
1698 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1699 && METHOD_OF_CODE(vftbl->table[pd->m->vftblindex]) == pd->m)
1701 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1705 void replace_patch_class_hierarchy(methodinfo *m,
1709 struct replace_patch_data_t pd;
1712 pd.oldentrypoint = oldentrypoint;
1713 pd.entrypoint = entrypoint;
1715 DOLOG_SHORT( printf("patching class hierarchy: ");
1716 method_println(m); );
1718 classcache_foreach_loaded_class(
1719 (classcache_foreach_functionptr_t) &replace_patch_callback,
1724 /* replace_patch_future_calls **************************************************
1726 Analyse a call site and depending on the kind of call patch the call, the
1727 virtual function table, or the interface table.
1730 ra...............return address pointing after the call site
1731 callerframe......source frame of the caller
1732 calleeframe......source frame of the callee, must have been mapped
1734 *******************************************************************************/
1736 void replace_patch_future_calls(u1 *ra,
1737 sourceframe_t *callerframe,
1738 sourceframe_t *calleeframe)
1741 methodptr entrypoint;
1742 methodptr oldentrypoint;
1745 codeinfo *calleecode;
1746 methodinfo *calleem;
1747 java_objectheader *obj;
1751 assert(callerframe->down == calleeframe);
1753 /* get the new codeinfo and the method that shall be entered */
1755 calleecode = calleeframe->tocode;
1758 calleem = calleeframe->method;
1759 assert(calleem == calleecode->m);
1761 entrypoint = (methodptr) calleecode->entrypoint;
1763 /* check if we are at an method entry rplpoint at the innermost frame */
1765 atentry = (calleeframe->down == NULL)
1766 && !(calleem->flags & ACC_STATIC)
1767 && (calleeframe->fromrp->id == 0); /* XXX */
1769 /* get the position to patch, in case it was a statically bound call */
1771 sfi.pv = callerframe->fromcode->entrypoint;
1772 patchpos = md_get_method_patch_address(ra, &sfi, NULL);
1774 if (patchpos == NULL) {
1775 /* the call was dispatched dynamically */
1777 /* we can only patch such calls if we are at the entry point */
1782 assert((calleem->flags & ACC_STATIC) == 0);
1784 oldentrypoint = calleeframe->fromcode->entrypoint;
1786 /* we need to know the instance */
1788 if (!calleeframe->instance.a) {
1789 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1790 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1796 obj = calleeframe->instance.a;
1799 assert(vftbl->class->vftbl == vftbl);
1801 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1803 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1806 /* the call was statically bound */
1808 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1813 /* replace_push_activation_record **********************************************
1815 Push a stack frame onto the execution state.
1817 *** This function imitates the effects of a call and the ***
1818 *** method prolog of the callee. ***
1821 es...............execution state
1822 rpcall...........the replacement point at the call site
1823 callerframe......source frame of the caller, or NULL for creating the
1825 calleeframe......source frame of the callee, must have been mapped
1828 *es..............the execution state after pushing the stack frame
1830 *******************************************************************************/
1832 void replace_push_activation_record(executionstate_t *es,
1834 sourceframe_t *callerframe,
1835 sourceframe_t *calleeframe)
1840 stackslot_t *basesp;
1843 codeinfo *calleecode;
1846 assert(!rpcall || callerframe);
1847 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1848 assert(!rpcall || rpcall == callerframe->torp);
1849 assert(calleeframe);
1850 assert(!callerframe || calleeframe == callerframe->down);
1852 /* the compilation unit we are entering */
1854 calleecode = calleeframe->tocode;
1857 /* calculate the return address */
1860 ra = rpcall->pc + rpcall->callsize;
1862 ra = es->pc + 1 /* XXX this is ugly */;
1864 /* write the return address */
1866 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1867 es->sp -= SIZE_OF_STACKSLOT;
1869 *((stackslot_t *)es->sp) = (stackslot_t) ra;
1870 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1872 #if defined(REPLACE_REG_RA)
1873 es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1876 /* we move into a new code unit */
1878 es->code = calleecode;
1880 /* set the new pc XXX not needed? */
1882 es->pc = calleecode->entrypoint;
1884 /* build the stackframe */
1886 DOLOG( printf("building stackframe of %d words at %p\n",
1887 calleecode->stackframesize, (void*)es->sp); );
1889 sp = (stackslot_t *) es->sp;
1892 sp -= calleecode->stackframesize;
1895 /* in debug mode, invalidate stack frame first */
1897 /* XXX may not invalidate linkage area used by native code! */
1898 #if !defined(NDEBUG) && 0
1899 for (i=0; i<(basesp - sp); ++i) {
1900 sp[i] = 0xdeaddeadU;
1904 /* save the return address register */
1906 #if defined(REPLACE_RA_TOP_OF_FRAME)
1907 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1908 if (!CODE_IS_LEAFMETHOD(calleecode))
1910 *--basesp = (ptrint) ra;
1911 #endif /* REPLACE_RA_TOP_OF_FRAME */
1913 #if defined(REPLACE_RA_LINKAGE_AREA)
1914 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1915 if (!CODE_IS_LEAFMETHOD(calleecode))
1917 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1918 #endif /* REPLACE_RA_LINKAGE_AREA */
1920 /* save int registers */
1923 for (i=0; i<calleecode->savedintcount; ++i) {
1924 while (nregdescint[--reg] != REG_SAV)
1926 *--basesp = es->intregs[reg];
1928 /* XXX may not clobber saved regs used by native code! */
1929 #if !defined(NDEBUG) && 0
1930 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1934 /* save flt registers */
1938 for (i=0; i<calleecode->savedfltcount; ++i) {
1939 while (nregdescfloat[--reg] != REG_SAV)
1941 basesp -= STACK_SLOTS_PER_FLOAT;
1942 *(double*)basesp = es->fltregs[reg];
1944 /* XXX may not clobber saved regs used by native code! */
1945 #if !defined(NDEBUG) && 0
1946 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1950 /* write slots used for synchronization */
1952 count = code_get_sync_slot_count(calleecode);
1953 assert(count == calleeframe->syncslotcount);
1954 for (i=0; i<count; ++i) {
1955 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
1960 es->pv = calleecode->entrypoint;
1962 /* redirect future invocations */
1964 if (callerframe && rpcall) {
1965 #if defined(REPLACE_PATCH_ALL)
1966 if (rpcall->type == callerframe->fromrp->type)
1968 if (rpcall == callerframe->fromrp)
1970 replace_patch_future_calls(ra, callerframe, calleeframe);
1975 /* replace_find_replacement_point **********************************************
1977 Find the replacement point in the given code corresponding to the
1978 position given in the source frame.
1981 code.............the codeinfo in which to search the rplpoint
1982 frame............the source frame defining the position to look for
1983 parent...........parent replacement point to match
1986 the replacement point
1988 *******************************************************************************/
1990 rplpoint * replace_find_replacement_point(codeinfo *code,
1991 sourceframe_t *frame,
2004 DOLOG( printf("searching replacement point for:\n");
2005 replace_source_frame_println(frame); );
2009 DOLOG( printf("code = %p\n", (void*)code); );
2011 rp = code->rplpoints;
2012 i = code->rplpointcount;
2014 if (rp->id == frame->id && rp->method == frame->method
2015 && rp->parent == parent
2016 && replace_normalize_type_map[rp->type] == frame->type)
2018 /* check if returnAddresses match */
2019 /* XXX optimize: only do this if JSRs in method */
2020 DOLOG( printf("checking match for:");
2021 replace_replacement_point_println(rp, 1); fflush(stdout); );
2024 for (j = rp->regalloccount; j--; ++ra) {
2025 if (ra->type == TYPE_RET) {
2026 if (ra->index == RPLALLOC_STACK) {
2027 assert(stacki < frame->javastackdepth);
2028 if (frame->javastack[stacki].i != ra->regoff)
2033 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2034 if (frame->javalocals[ra->index].i != ra->regoff)
2047 #if !defined(NDEBUG)
2048 printf("candidate replacement points were:\n");
2049 rp = code->rplpoints;
2050 i = code->rplpointcount;
2052 replace_replacement_point_println(rp, 1);
2056 vm_abort("no matching replacement point found");
2057 return NULL; /* NOT REACHED */
2061 /* replace_find_replacement_point_for_pc ***************************************
2063 Find the nearest replacement point at or before the given PC.
2066 code.............compilation unit the PC is in
2067 pc...............the machine code PC
2070 the replacement point found, or
2071 NULL if no replacement point was found
2073 *******************************************************************************/
2075 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2081 DOLOG( printf("searching for rp in %p ", (void*)code);
2082 method_println(code->m);
2083 printf("PC = %p\n", (void*)pc); );
2087 rp = code->rplpoints;
2088 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2089 DOLOG( replace_replacement_point_println(rp, 2); );
2094 assert(found->pc + found->callsize >= pc);
2100 /* replace_pop_native_frame ****************************************************
2102 Unroll a native frame in the execution state and create a source frame
2106 es...............current execution state
2107 ss...............the current source state
2108 sfi..............stackframeinfo for the native frame
2111 es...............execution state after unrolling the native frame
2112 ss...............gets the added native source frame
2114 *******************************************************************************/
2116 static void replace_pop_native_frame(executionstate_t *es,
2118 stackframeinfo *sfi)
2120 sourceframe_t *frame;
2126 frame = replace_new_sourceframe(ss);
2130 /* remember pc and size of native frame */
2132 frame->nativepc = es->pc;
2133 frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2134 assert(frame->nativeframesize >= 0);
2136 /* remember values of saved registers */
2139 for (i=0; i<INT_REG_CNT; ++i) {
2140 if (nregdescint[i] == REG_SAV)
2141 frame->nativesavint[j++] = es->intregs[i];
2145 for (i=0; i<FLT_REG_CNT; ++i) {
2146 if (nregdescfloat[i] == REG_SAV)
2147 frame->nativesavflt[j++] = es->fltregs[i];
2150 /* restore saved registers */
2152 #if defined(ENABLE_GC_CACAO)
2154 for (i=0; i<INT_REG_CNT; ++i) {
2155 if (nregdescint[i] == REG_SAV)
2156 es->intregs[i] = sfi->intregs[j++];
2159 /* XXX we don't have them, yet, in the sfi, so clear them */
2161 for (i=0; i<INT_REG_CNT; ++i) {
2162 if (nregdescint[i] == REG_SAV)
2167 /* XXX we don't have float registers in the sfi, so clear them */
2169 for (i=0; i<FLT_REG_CNT; ++i) {
2170 if (nregdescfloat[i] == REG_SAV)
2171 es->fltregs[i] = 0.0;
2174 /* restore pv, pc, and sp */
2176 if (sfi->pv == NULL) {
2177 /* frame of a native function call */
2178 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2183 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2186 /* find the new codeinfo */
2188 DOLOG( printf("PV = %p\n", (void*) es->pv); );
2190 assert(es->pv != NULL);
2192 code = *(codeinfo **)(es->pv + CodeinfoPointer);
2194 DOLOG( printf("CODE = %p\n", (void*) code); );
2200 /* replace_push_native_frame ***************************************************
2202 Rebuild a native frame onto the execution state and remove its source frame.
2204 Note: The native frame is "rebuild" by setting fields like PC and stack
2205 pointer in the execution state accordingly. Values in the
2206 stackframeinfo may be modified, but the actual stack frame of the
2207 native code is not touched.
2210 es...............current execution state
2211 ss...............the current source state
2214 es...............execution state after re-rolling the native frame
2215 ss...............the native source frame is removed
2217 *******************************************************************************/
2219 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2221 sourceframe_t *frame;
2227 DOLOG( printf("pushing native frame\n"); );
2229 /* remove the frame from the source state */
2233 assert(REPLACE_IS_NATIVE_FRAME(frame));
2235 ss->frames = frame->down;
2237 /* assert that the native frame has not moved */
2239 assert(es->sp == frame->sfi->sp);
2241 /* update saved registers in the stackframeinfo */
2243 #if defined(ENABLE_GC_CACAO)
2245 for (i=0; i<INT_REG_CNT; ++i) {
2246 if (nregdescint[i] == REG_SAV)
2247 frame->sfi->intregs[j++] = es->intregs[i];
2250 /* XXX leave float registers untouched here */
2253 /* restore saved registers */
2256 for (i=0; i<INT_REG_CNT; ++i) {
2257 if (nregdescint[i] == REG_SAV)
2258 es->intregs[i] = frame->nativesavint[j++];
2262 for (i=0; i<FLT_REG_CNT; ++i) {
2263 if (nregdescfloat[i] == REG_SAV)
2264 es->fltregs[i] = frame->nativesavflt[j++];
2267 /* skip the native frame on the machine stack */
2269 es->sp -= frame->nativeframesize;
2271 /* set the pc the next frame must return to */
2273 es->pc = frame->nativepc;
2277 /* replace_recover_source_state ************************************************
2279 Recover the source state from the given replacement point and execution
2283 rp...............replacement point that has been reached, if any
2284 sfi..............stackframeinfo, if called from native code
2285 es...............execution state at the replacement point rp
2290 *******************************************************************************/
2292 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2293 stackframeinfo *sfi,
2294 executionstate_t *es)
2299 #if defined(REPLACE_STATISTICS)
2303 /* create the source frame structure in dump memory */
2305 ss = DNEW(sourcestate_t);
2308 /* each iteration of the loop recovers one source frame */
2315 DOLOG( replace_executionstate_println(es); );
2317 /* if we are not at a replacement point, it is a native frame */
2320 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2323 replace_pop_native_frame(es, ss, sfi);
2326 if (es->code == NULL)
2329 goto after_machine_frame;
2332 /* read the values for this source frame from the execution state */
2334 DOLOG( printf("recovering source state for%s:\n",
2335 (ss->frames == NULL) ? " TOPFRAME" : "");
2336 replace_replacement_point_println(rp, 1); );
2338 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2340 #if defined(ENABLE_VMLOG)
2341 vmlog_cacao_unrol_method(ss->frames->method);
2344 #if defined(REPLACE_STATISTICS)
2345 REPLACE_COUNT(stat_frames);
2347 replace_statistics_source_frame(ss->frames);
2350 /* in locked areas (below native frames), identity map the frame */
2353 ss->frames->torp = ss->frames->fromrp;
2354 ss->frames->tocode = ss->frames->fromcode;
2357 /* unroll to the next (outer) frame */
2360 /* this frame is in inlined code */
2362 DOLOG( printf("INLINED!\n"); );
2366 assert(rp->type == RPLPOINT_TYPE_INLINE);
2367 REPLACE_COUNT(stat_unroll_inline);
2370 /* this frame had been called at machine-level. pop it. */
2372 DOLOG( printf("UNWIND\n"); );
2374 ra = replace_pop_activation_record(es, ss->frames);
2376 DOLOG( printf("REACHED NATIVE CODE\n"); );
2380 #if !defined(ENABLE_GC_CACAO)
2381 break; /* XXX remove to activate native frames */
2386 /* find the replacement point at the call site */
2388 after_machine_frame:
2389 rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2392 vm_abort("could not find replacement point while unrolling call");
2394 DOLOG( printf("found replacement point.\n");
2395 replace_replacement_point_println(rp, 1); );
2397 assert(rp->type == RPLPOINT_TYPE_CALL);
2398 REPLACE_COUNT(stat_unroll_call);
2400 } /* end loop over source frames */
2402 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2408 /* replace_map_source_state ****************************************************
2410 Map each source frame in the given source state to a target replacement
2411 point and compilation unit. If no valid code is available for a source
2412 frame, it is (re)compiled.
2415 ss...............the source state
2418 ss...............the source state, modified: The `torp` and `tocode`
2419 fields of each source frame are set.
2422 true.............everything went ok
2423 false............an exception has been thrown
2425 *******************************************************************************/
2427 static bool replace_map_source_state(sourcestate_t *ss)
2429 sourceframe_t *frame;
2432 rplpoint *parent; /* parent of inlined rplpoint */
2433 #if defined(REPLACE_STATISTICS)
2440 /* iterate over the source frames from outermost to innermost */
2442 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2444 /* XXX skip native frames */
2446 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2451 /* map frames which are not already mapped */
2453 if (frame->tocode) {
2454 code = frame->tocode;
2459 assert(frame->torp == NULL);
2461 if (parent == NULL) {
2462 /* find code for this frame */
2464 #if defined(REPLACE_STATISTICS)
2465 oldcode = frame->method->code;
2467 /* request optimization of hot methods and their callers */
2469 if (frame->method->hitcountdown < 0
2470 || (frame->down && frame->down->method->hitcountdown < 0))
2471 jit_request_optimization(frame->method);
2473 code = jit_get_current_code(frame->method);
2476 return false; /* exception */
2478 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2483 /* map this frame */
2485 rp = replace_find_replacement_point(code, frame, parent);
2487 frame->tocode = code;
2491 if (rp->type == RPLPOINT_TYPE_CALL) {
2504 /* replace_map_source_state_identity *******************************************
2506 Map each source frame in the given source state to the same replacement
2507 point and compilation unit it was derived from. This is mainly used for
2511 ss...............the source state
2514 ss...............the source state, modified: The `torp` and `tocode`
2515 fields of each source frame are set.
2517 *******************************************************************************/
2519 #if defined(ENABLE_GC_CACAO)
2520 static void replace_map_source_state_identity(sourcestate_t *ss)
2522 sourceframe_t *frame;
2524 /* iterate over the source frames from outermost to innermost */
2526 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2528 /* skip native frames */
2530 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2534 /* map frames using the identity mapping */
2536 if (frame->tocode) {
2537 assert(frame->tocode == frame->fromcode);
2538 assert(frame->torp == frame->fromrp);
2540 assert(frame->tocode == NULL);
2541 assert(frame->torp == NULL);
2542 frame->tocode = frame->fromcode;
2543 frame->torp = frame->fromrp;
2550 /* replace_build_execution_state_intern ****************************************
2552 Build an execution state for the given (mapped) source state.
2554 !!! CAUTION: This function rewrites the machine stack !!!
2556 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2559 ss...............the source state. Must have been mapped by
2560 replace_map_source_state before.
2561 es...............the base execution state on which to build
2564 *es..............the new execution state
2566 *******************************************************************************/
2568 void replace_build_execution_state_intern(sourcestate_t *ss,
2569 executionstate_t *es)
2572 sourceframe_t *prevframe;
2579 while (ss->frames) {
2581 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2582 prevframe = ss->frames;
2583 replace_push_native_frame(es, ss);
2589 if (parent == NULL) {
2590 /* create a machine-level stack frame */
2592 DOLOG( printf("pushing activation record for:\n");
2593 if (rp) replace_replacement_point_println(rp, 1);
2594 else printf("\tfirst frame\n"); );
2596 replace_push_activation_record(es, rp, prevframe, ss->frames);
2598 DOLOG( replace_executionstate_println(es); );
2601 rp = ss->frames->torp;
2604 DOLOG( printf("creating execution state for%s:\n",
2605 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2606 replace_replacement_point_println(ss->frames->fromrp, 1);
2607 replace_replacement_point_println(rp, 1); );
2609 es->code = ss->frames->tocode;
2610 prevframe = ss->frames;
2612 #if defined(ENABLE_VMLOG)
2613 vmlog_cacao_rerol_method(ss->frames->method);
2616 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2618 DOLOG( replace_executionstate_println(es); );
2620 if (rp->type == RPLPOINT_TYPE_CALL) {
2631 /* replace_build_execution_state ***********************************************
2633 This function contains the final phase of replacement. It builds the new
2634 execution state, releases dump memory, and returns to the calling
2635 assembler function which finishes replacement.
2637 NOTE: This function is called from asm_replacement_in, with the stack
2638 pointer at the start of the safe stack area.
2640 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2642 CAUTION: This function and its children must not use a lot of stack!
2643 There are only REPLACE_SAFESTACK_SIZE bytes of C stack
2647 st...............the safestack contained the necessary data
2649 *******************************************************************************/
2651 void replace_build_execution_state(replace_safestack_t *st)
2653 replace_build_execution_state_intern(st->ss, &(st->es));
2655 DOLOG( replace_executionstate_println(&(st->es)); );
2657 /* release dump area */
2659 dump_release(st->dumpsize);
2661 /* new code is entered after returning */
2663 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2667 /* replace_alloc_safestack *****************************************************
2669 Allocate a safe stack area to use during the final phase of replacement.
2670 The returned area is not initialized. This must be done by the caller.
2673 a newly allocated replace_safestack_t *
2675 *******************************************************************************/
2677 static replace_safestack_t *replace_alloc_safestack()
2680 replace_safestack_t *st;
2682 mem = MNEW(u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2684 st = (replace_safestack_t *) ((ptrint)(mem + REPLACE_STACK_ALIGNMENT - 1)
2685 & ~(REPLACE_STACK_ALIGNMENT - 1));
2687 #if !defined(NDEBUG)
2688 memset(st, 0xa5, sizeof(replace_safestack_t));
2697 /* replace_free_safestack ******************************************************
2699 Free the given safestack structure, making a copy of the contained
2700 execution state before freeing it.
2702 NOTE: This function is called from asm_replacement_in.
2705 st...............the safestack to free
2706 tmpes............where to copy the execution state to
2709 *tmpes...........receives a copy of st->es
2711 *******************************************************************************/
2713 void replace_free_safestack(replace_safestack_t *st, executionstate_t *tmpes)
2717 /* copy the executionstate_t to the temporary location */
2721 /* get the memory address to free */
2725 /* destroy memory (in debug mode) */
2727 #if !defined(NDEBUG)
2728 memset(st, 0xa5, sizeof(replace_safestack_t));
2731 /* free the safe stack struct */
2733 MFREE(mem, u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2737 /* replace_me ******************************************************************
2739 This function is called by asm_replacement_out when a thread reaches
2740 a replacement point. `replace_me` must map the execution state to the
2741 target replacement point and let execution continue there.
2743 This function never returns!
2746 rp...............replacement point that has been reached
2747 es...............execution state read by asm_replacement_out
2749 *******************************************************************************/
2751 void replace_me(rplpoint *rp, executionstate_t *es)
2753 stackframeinfo *sfi;
2755 sourceframe_t *frame;
2758 replace_safestack_t *safestack;
2759 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2760 threadobject *thread;
2764 es->code = code_find_codeinfo_for_pc(rp->pc);
2766 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2767 stat_replacements, (void*)THREADOBJECT,
2769 method_println(es->code->m); );
2771 DOLOG( replace_replacement_point_println(rp, 1);
2772 replace_executionstate_println(es); );
2774 REPLACE_COUNT(stat_replacements);
2776 /* mark start of dump memory area */
2778 dumpsize = dump_size();
2780 /* get the stackframeinfo for the current thread */
2782 sfi = STACKFRAMEINFO;
2784 /* recover source state */
2786 ss = replace_recover_source_state(rp, sfi, es);
2788 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2789 /* if there is a collection pending, we assume the replacement point should
2790 suspend this thread */
2794 thread = THREADOBJECT;
2796 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2798 /* map the sourcestate using the identity mapping */
2799 replace_map_source_state_identity(ss);
2801 /* since we enter the same method again, we turn off rps now */
2802 /* XXX michi: can we really do this? what if the rp was active before
2803 we activated it for the gc? */
2806 frame = frame->down;
2807 replace_deactivate_replacement_points(frame->tocode);
2809 /* remember executionstate and sourcestate for this thread */
2810 GC_EXECUTIONSTATE = es;
2811 GC_SOURCESTATE = ss;
2813 /* really suspend this thread now (PC = 0) */
2814 threads_suspend_ack(NULL, NULL);
2816 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2819 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2821 /* map the source state */
2823 if (!replace_map_source_state(ss))
2824 vm_abort("exception during method replacement");
2826 DOLOG( replace_sourcestate_println(ss); );
2828 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2830 /* avoid infinite loops by self-replacement */
2834 frame = frame->down;
2836 if (frame->torp == origrp) {
2838 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2840 replace_deactivate_replacement_points(frame->tocode);
2843 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2847 /* write execution state of new code */
2849 DOLOG( replace_executionstate_println(es); );
2851 /* allocate a safe stack area and copy all needed data there */
2853 safestack = replace_alloc_safestack();
2855 safestack->es = *es;
2857 safestack->dumpsize = dumpsize;
2859 /* call the assembler code for the last phase of replacement */
2861 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
2862 asm_replacement_in(&(safestack->es), safestack);
2865 abort(); /* NOT REACHED */
2869 /******************************************************************************/
2870 /* NOTE: Stuff specific to the exact GC is below. */
2871 /******************************************************************************/
2873 #if defined(ENABLE_GC_CACAO)
2874 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
2876 stackframeinfo *sfi;
2877 executionstate_t *es;
2880 /* get the stackframeinfo of this thread */
2881 assert(thread == THREADOBJECT);
2882 sfi = STACKFRAMEINFO;
2884 /* create the execution state */
2885 es = DNEW(executionstate_t);
2888 es->pv = 0; /* since we are in a native, PV is invalid! */
2889 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
2891 /* we assume we are in a native (no replacement point)! */
2892 ss = replace_recover_source_state(NULL, sfi, es);
2894 /* map the sourcestate using the identity mapping */
2895 replace_map_source_state_identity(ss);
2897 /* remember executionstate and sourcestate for this thread */
2898 GC_EXECUTIONSTATE = es;
2899 GC_SOURCESTATE = ss;
2904 /******************************************************************************/
2905 /* NOTE: No important code below. */
2906 /******************************************************************************/
2909 /* statistics *****************************************************************/
2911 #if defined(REPLACE_STATISTICS)
2912 static void print_freq(FILE *file,int *array,int limit)
2917 for (i=0; i<limit; ++i)
2919 sum += array[limit];
2920 for (i=0; i<limit; ++i) {
2922 fprintf(file," %3d: %8d (cum %3d%%)\n",
2923 i, array[i], (sum) ? ((100*cum)/sum) : 0);
2925 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
2927 #endif /* defined(REPLACE_STATISTICS) */
2930 #if defined(REPLACE_STATISTICS)
2932 #define REPLACE_PRINT_DIST(name, array) \
2933 printf(" " name " distribution:\n"); \
2934 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
2936 void replace_print_statistics(void)
2938 printf("replacement statistics:\n");
2939 printf(" # of replacements: %d\n", stat_replacements);
2940 printf(" # of frames: %d\n", stat_frames);
2941 printf(" # of recompilations: %d\n", stat_recompile);
2942 printf(" patched static calls:%d\n", stat_staticpatch);
2943 printf(" unrolled inlines: %d\n", stat_unroll_inline);
2944 printf(" unrolled calls: %d\n", stat_unroll_call);
2945 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
2946 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
2947 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
2948 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
2949 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
2950 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
2951 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
2952 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
2953 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
2954 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
2956 printf(" # of methods: %d\n", stat_methods);
2957 printf(" # of replacement points: %d\n", stat_rploints);
2958 printf(" # of regallocs: %d\n", stat_regallocs);
2959 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
2960 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
2961 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
2965 #endif /* defined(REPLACE_STATISTICS) */
2968 #if defined(REPLACE_STATISTICS)
2969 static void replace_statistics_source_frame(sourceframe_t *frame)
2978 for (i=0; i<frame->javalocalcount; ++i) {
2979 switch (frame->javalocaltype[i]) {
2980 case TYPE_ADR: adr++; break;
2981 case TYPE_RET: ret++; break;
2982 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
2983 case TYPE_VOID: vd++; break;
2988 REPLACE_COUNT_DIST(stat_dist_locals, n);
2989 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
2990 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
2991 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
2992 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
2993 adr = ret = prim = n = 0;
2994 for (i=0; i<frame->javastackdepth; ++i) {
2995 switch (frame->javastacktype[i]) {
2996 case TYPE_ADR: adr++; break;
2997 case TYPE_RET: ret++; break;
2998 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3002 REPLACE_COUNT_DIST(stat_dist_stack, n);
3003 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3004 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3005 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3007 #endif /* defined(REPLACE_STATISTICS) */
3010 /* debugging helpers **********************************************************/
3012 /* replace_replacement_point_println *******************************************
3014 Print replacement point info.
3017 rp...............the replacement point to print
3019 *******************************************************************************/
3021 #if !defined(NDEBUG)
3023 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3025 static char *replace_type_str[] = {
3035 void replace_replacement_point_println(rplpoint *rp, int depth)
3041 printf("(rplpoint *)NULL\n");
3045 for (j=0; j<depth; ++j)
3048 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3049 rp->id, (void*)rp,rp->pc,rp->callsize,
3050 replace_type_str[rp->type]);
3051 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3053 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3054 printf(" COUNTDOWN");
3055 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3057 printf(" parent:%p\n", (void*)rp->parent);
3058 for (j=0; j<depth; ++j)
3060 printf("ra:%d = [", rp->regalloccount);
3062 for (j=0; j<rp->regalloccount; ++j) {
3065 index = rp->regalloc[j].index;
3067 case RPLALLOC_STACK: printf("S"); break;
3068 case RPLALLOC_PARAM: printf("P"); break;
3069 case RPLALLOC_SYNC : printf("Y"); break;
3070 default: printf("%d", index);
3072 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3073 if (rp->regalloc[j].type == TYPE_RET) {
3074 printf("ret(L%03d)", rp->regalloc[j].regoff);
3077 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3082 for (j=0; j<depth; ++j)
3085 method_print(rp->method);
3089 #endif /* !defined(NDEBUG) */
3092 /* replace_show_replacement_points *********************************************
3094 Print replacement point info.
3097 code.............codeinfo whose replacement points should be printed.
3099 *******************************************************************************/
3101 #if !defined(NDEBUG)
3102 void replace_show_replacement_points(codeinfo *code)
3110 printf("(codeinfo *)NULL\n");
3114 printf("\treplacement points: %d\n",code->rplpointcount);
3116 printf("\ttotal allocations : %d\n",code->regalloccount);
3117 printf("\tsaved int regs : %d\n",code->savedintcount);
3118 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3119 printf("\tmemuse : %d\n",code->memuse);
3123 for (i=0; i<code->rplpointcount; ++i) {
3124 rp = code->rplpoints + i;
3127 parent = rp->parent;
3130 parent = parent->parent;
3132 replace_replacement_point_println(rp, depth);
3138 /* replace_executionstate_println **********************************************
3140 Print execution state
3143 es...............the execution state to print
3145 *******************************************************************************/
3147 #if !defined(NDEBUG)
3148 void replace_executionstate_println(executionstate_t *es)
3156 printf("(executionstate_t *)NULL\n");
3160 printf("executionstate_t:\n");
3161 printf("\tpc = %p",(void*)es->pc);
3162 printf(" sp = %p",(void*)es->sp);
3163 printf(" pv = %p\n",(void*)es->pv);
3164 #if defined(ENABLE_DISASSEMBLER)
3165 for (i=0; i<INT_REG_CNT; ++i) {
3170 #if SIZEOF_VOID_P == 8
3171 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3173 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3178 for (i=0; i<FLT_REG_CNT; ++i) {
3183 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3189 sp = (stackslot_t *) es->sp;
3194 methoddesc *md = es->code->m->parseddesc;
3195 slots = code_get_stack_frame_size(es->code);
3196 extraslots = 1 + md->memuse;
3203 printf("\tstack slots(+%d) at sp:", extraslots);
3204 for (i=0; i<slots+extraslots; ++i) {
3207 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3208 #ifdef HAS_4BYTE_STACKSLOT
3209 printf("%08lx",(unsigned long)*sp++);
3211 printf("%016llx",(unsigned long long)*sp++);
3213 printf("%c", (i >= slots) ? ')' : ' ');
3218 printf("\tcode: %p", (void*)es->code);
3219 if (es->code != NULL) {
3220 printf(" stackframesize=%d ", es->code->stackframesize);
3221 method_print(es->code->m);
3229 #if !defined(NDEBUG)
3230 static void java_value_print(s4 type, replace_val_t value)
3232 java_objectheader *obj;
3235 printf("%016llx",(unsigned long long) value.l);
3237 if (type < 0 || type > TYPE_RET)
3238 printf(" <INVALID TYPE:%d>", type);
3240 printf(" %s", show_jit_type_names[type]);
3242 if (type == TYPE_ADR && value.a != NULL) {
3245 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3247 if (obj->vftbl->class == class_java_lang_String) {
3249 u = javastring_toutf(obj, false);
3250 utf_display_printable_ascii(u);
3254 else if (type == TYPE_INT) {
3255 printf(" %ld", (long) value.i);
3257 else if (type == TYPE_LNG) {
3258 printf(" %lld", (long long) value.l);
3260 else if (type == TYPE_FLT) {
3261 printf(" %f", value.f);
3263 else if (type == TYPE_DBL) {
3264 printf(" %f", value.d);
3267 #endif /* !defined(NDEBUG) */
3270 #if !defined(NDEBUG)
3271 void replace_source_frame_println(sourceframe_t *frame)
3276 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3277 printf("\tNATIVE\n");
3278 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3279 printf("\tnativepc: %p\n", frame->nativepc);
3280 printf("\tframesize: %d\n", frame->nativeframesize);
3283 for (i=0; i<INT_REG_CNT; ++i) {
3284 if (nregdescint[i] == REG_SAV)
3285 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3289 for (i=0; i<FLT_REG_CNT; ++i) {
3290 if (nregdescfloat[i] == REG_SAV)
3291 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3299 method_println(frame->method);
3300 printf("\tid: %d\n", frame->id);
3301 printf("\ttype: %s\n", replace_type_str[frame->type]);
3304 if (frame->instance.a) {
3305 printf("\tinstance: ");
3306 java_value_print(TYPE_ADR, frame->instance);
3310 if (frame->javalocalcount) {
3311 printf("\tlocals (%d):\n",frame->javalocalcount);
3312 for (i=0; i<frame->javalocalcount; ++i) {
3313 t = frame->javalocaltype[i];
3314 if (t == TYPE_VOID) {
3315 printf("\tlocal[ %2d] = void\n",i);
3318 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3319 java_value_print(t, frame->javalocals[i]);
3326 if (frame->javastackdepth) {
3327 printf("\tstack (depth %d):\n",frame->javastackdepth);
3328 for (i=0; i<frame->javastackdepth; ++i) {
3329 t = frame->javastacktype[i];
3330 if (t == TYPE_VOID) {
3331 printf("\tstack[%2d] = void", i);
3334 printf("\tstack[%2d] = ",i);
3335 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3342 if (frame->syncslotcount) {
3343 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3344 for (i=0; i<frame->syncslotcount; ++i) {
3345 printf("\tslot[%2d] = ",i);
3346 #ifdef HAS_4BYTE_STACKSLOT
3347 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3349 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3355 if (frame->fromcode) {
3356 printf("\tfrom %p ", (void*)frame->fromcode);
3357 method_println(frame->fromcode->m);
3359 if (frame->tocode) {
3360 printf("\tto %p ", (void*)frame->tocode);
3361 method_println(frame->tocode->m);
3364 if (frame->fromrp) {
3365 printf("\tfrom replacement point:\n");
3366 replace_replacement_point_println(frame->fromrp, 2);
3369 printf("\tto replacement point:\n");
3370 replace_replacement_point_println(frame->torp, 2);
3375 #endif /* !defined(NDEBUG) */
3378 /* replace_sourcestate_println *************************************************
3383 ss...............the source state to print
3385 *******************************************************************************/
3387 #if !defined(NDEBUG)
3388 void replace_sourcestate_println(sourcestate_t *ss)
3391 sourceframe_t *frame;
3394 printf("(sourcestate_t *)NULL\n");
3398 printf("sourcestate_t:\n");
3400 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3401 printf(" frame %d:\n", i);
3402 replace_source_frame_println(frame);
3408 /* replace_sourcestate_println_short *******************************************
3410 Print a compact representation of the given source state.
3413 ss...............the source state to print
3415 *******************************************************************************/
3417 #if !defined(NDEBUG)
3418 void replace_sourcestate_println_short(sourcestate_t *ss)
3420 sourceframe_t *frame;
3422 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3425 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3426 printf("NATIVE (pc %p size %d) ",
3427 (void*)frame->nativepc, frame->nativeframesize);
3428 replace_stackframeinfo_println(frame->sfi);
3433 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3436 printf("%s", replace_type_str[frame->fromrp->type]);
3438 if (frame->torp && frame->torp->type != frame->fromrp->type)
3439 printf("->%s", replace_type_str[frame->torp->type]);
3441 if (frame->tocode != frame->fromcode)
3442 printf(" (%p->%p/%d) ",
3443 (void*) frame->fromcode, (void*) frame->tocode,
3446 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3448 method_println(frame->method);
3453 #if !defined(NDEBUG)
3454 static void replace_stackframeinfo_println(stackframeinfo *sfi)
3456 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3457 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3458 (void*)sfi->ra, (void*)sfi->xpc);
3461 method_println(sfi->method);
3468 * These are local overrides for various environment variables in Emacs.
3469 * Please do not remove this and leave it at the end of the file, where
3470 * Emacs will automagically detect them.
3471 * ---------------------------------------------------------------------
3474 * indent-tabs-mode: t
3478 * vim:noexpandtab:sw=4:ts=4: