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*/
67 /*** architecture-dependent configuration *************************************/
69 /* first unset the macros (default) */
70 #undef REPLACE_RA_BETWEEN_FRAMES
71 #undef REPLACE_RA_TOP_OF_FRAME
72 #undef REPLACE_RA_LINKAGE_AREA
73 #undef REPLACE_LEAFMETHODS_RA_REGISTER
77 #if defined(__I386__) || defined(__X86_64__)
78 #define REPLACE_RA_BETWEEN_FRAMES
80 #elif defined(__ALPHA__)
81 #define REPLACE_RA_TOP_OF_FRAME
82 #define REPLACE_LEAFMETHODS_RA_REGISTER
83 #define REPLACE_REG_RA REG_RA
85 #elif defined(__POWERPC__)
86 #define REPLACE_RA_LINKAGE_AREA
87 #define REPLACE_LEAFMETHODS_RA_REGISTER
88 #define REPLACE_REG_RA REG_ITMP3 /* the execution state has the LR in itmp3 */
92 /*** configuration of native stack slot size **********************************/
94 /* XXX this should be in md-abi.h files, probably */
96 #if defined(HAS_4BYTE_STACKSLOT)
97 #define SIZE_OF_STACKSLOT 4
98 #define STACK_SLOTS_PER_FLOAT 2
99 typedef u4 stackslot_t;
101 #define SIZE_OF_STACKSLOT 8
102 #define STACK_SLOTS_PER_FLOAT 1
103 typedef u8 stackslot_t;
107 /*** debugging ****************************************************************/
109 /*#define REPLACE_VERBOSE*/
112 static void java_value_print(s4 type, replace_val_t value);
113 static void replace_stackframeinfo_println(stackframeinfo *sfi);
116 #if !defined(NDEBUG) && defined(REPLACE_VERBOSE)
117 int replace_verbose = 0;
118 #define DOLOG(code) do{ if (replace_verbose > 1) { code; } } while(0)
119 #define DOLOG_SHORT(code) do{ if (replace_verbose > 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];
250 if (index < UNUSED) {
251 ra->regoff = (UNUSED - index) - 1;
257 ra->flags = v->flags & (INMEMORY);
258 ra->regoff = v->vv.regoff;
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 code->memuse = rd->memuse;
717 code->stackframesize = jd->cd->stackframesize;
719 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
720 REPLACE_COUNT_INC(stat_regallocs, alloccount);
722 /* everything alright */
728 /* replace_free_replacement_points *********************************************
730 Free memory used by replacement points.
733 code.............codeinfo whose replacement points should be freed.
735 *******************************************************************************/
737 void replace_free_replacement_points(codeinfo *code)
742 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
745 MFREE(code->regalloc,rplalloc,code->regalloccount);
747 code->rplpoints = NULL;
748 code->rplpointcount = 0;
749 code->regalloc = NULL;
750 code->regalloccount = 0;
751 code->globalcount = 0;
755 /******************************************************************************/
756 /* PART II: Activating / deactivating replacement points */
757 /******************************************************************************/
760 /* replace_activate_replacement_points *****************************************
762 Activate the replacement points of the given compilation unit. When this
763 function returns, the replacement points are "armed", so each thread
764 reaching one of the points will enter the replacement mechanism.
767 code.............codeinfo of which replacement points should be
769 mappable.........if true, only mappable replacement points are
772 *******************************************************************************/
774 void replace_activate_replacement_points(codeinfo *code, bool mappable)
782 assert(code->savedmcode == NULL);
784 /* count trappable replacement points */
788 i = code->rplpointcount;
789 rp = code->rplpoints;
791 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
796 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
802 /* allocate buffer for saved machine code */
804 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
805 code->savedmcode = savedmcode;
806 savedmcode += count * REPLACEMENT_PATCH_SIZE;
808 /* activate trappable replacement points */
809 /* (in reverse order to handle overlapping points within basic blocks) */
811 i = code->rplpointcount;
812 rp = code->rplpoints + i;
814 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
816 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
821 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
824 DOLOG( printf("activate replacement point:\n");
825 replace_replacement_point_println(rp, 1); fflush(stdout); );
827 savedmcode -= REPLACEMENT_PATCH_SIZE;
829 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
830 md_patch_replacement_point(code, index, rp, savedmcode);
832 rp->flags |= RPLPOINT_FLAG_ACTIVE;
835 assert(savedmcode == code->savedmcode);
839 /* replace_deactivate_replacement_points ***************************************
841 Deactivate a replacement points in the given compilation unit.
842 When this function returns, the replacement points will be "un-armed",
843 that is a each thread reaching a point will just continue normally.
846 code.............the compilation unit
848 *******************************************************************************/
850 void replace_deactivate_replacement_points(codeinfo *code)
857 if (code->savedmcode == NULL) {
858 /* disarm countdown points by patching the branches */
860 i = code->rplpointcount;
861 rp = code->rplpoints;
863 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
864 == RPLPOINT_FLAG_COUNTDOWN)
867 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
874 assert(code->savedmcode != NULL);
875 savedmcode = code->savedmcode;
877 /* de-activate each trappable replacement point */
879 i = code->rplpointcount;
880 rp = code->rplpoints;
883 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
888 DOLOG( printf("deactivate replacement point:\n");
889 replace_replacement_point_println(rp, 1); fflush(stdout); );
891 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
892 md_patch_replacement_point(code, -1, rp, savedmcode);
895 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
897 savedmcode += REPLACEMENT_PATCH_SIZE;
900 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
902 /* free saved machine code */
904 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
905 code->savedmcode = NULL;
909 /******************************************************************************/
910 /* PART III: The replacement mechanism */
911 /******************************************************************************/
914 /* replace_read_value **********************************************************
916 Read a value with the given allocation from the execution state.
919 es...............execution state
920 sp...............stack pointer of the execution state (XXX eliminate?)
921 ra...............allocation
922 javaval..........where to put the value
925 *javaval.........the value
927 *******************************************************************************/
929 static void replace_read_value(executionstate_t *es,
932 replace_val_t *javaval)
934 if (ra->flags & INMEMORY) {
935 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
936 #ifdef HAS_4BYTE_STACKSLOT
937 if (IS_2_WORD_TYPE(ra->type)) {
938 javaval->l = *(u8*)(sp + ra->regoff);
942 javaval->p = sp[ra->regoff];
943 #ifdef HAS_4BYTE_STACKSLOT
948 /* allocated register */
949 if (IS_FLT_DBL_TYPE(ra->type)) {
950 javaval->d = es->fltregs[ra->regoff];
952 if (ra->type == TYPE_FLT)
953 javaval->f = javaval->d;
956 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
957 if (ra->type == TYPE_LNG) {
958 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
959 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
962 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
963 javaval->p = es->intregs[ra->regoff];
969 /* replace_write_value *********************************************************
971 Write a value to the given allocation in the execution state.
974 es...............execution state
975 sp...............stack pointer of the execution state (XXX eliminate?)
976 ra...............allocation
977 *javaval.........the value
979 *******************************************************************************/
981 static void replace_write_value(executionstate_t *es,
984 replace_val_t *javaval)
986 if (ra->flags & INMEMORY) {
987 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
988 #ifdef HAS_4BYTE_STACKSLOT
989 if (IS_2_WORD_TYPE(ra->type)) {
990 *(u8*)(sp + ra->regoff) = javaval->l;
994 sp[ra->regoff] = javaval->p;
995 #ifdef HAS_4BYTE_STACKSLOT
1000 /* allocated register */
1003 es->fltregs[ra->regoff] = (double) javaval->f;
1006 es->fltregs[ra->regoff] = javaval->d;
1008 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1010 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1011 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1015 es->intregs[ra->regoff] = javaval->p;
1021 /* replace_read_executionstate *************************************************
1023 Read the given executions state and translate it to a source frame.
1026 ss...............the source state
1029 ss->frames.......set to new frame
1032 returns the new frame
1034 *******************************************************************************/
1036 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1038 sourceframe_t *frame;
1040 frame = DNEW(sourceframe_t);
1041 MZERO(frame, sourceframe_t, 1);
1043 frame->down = ss->frames;
1050 /* replace_read_executionstate *************************************************
1052 Read the given executions state and translate it to a source frame.
1055 rp...............replacement point at which `es` was taken
1056 es...............execution state
1057 ss...............where to put the source state
1060 *ss..............the source state derived from the execution state
1062 *******************************************************************************/
1064 static s4 replace_normalize_type_map[] = {
1065 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1066 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1067 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1068 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1069 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1070 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1071 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1075 static void replace_read_executionstate(rplpoint *rp,
1076 executionstate_t *es,
1085 sourceframe_t *frame;
1088 stackslot_t *basesp;
1090 code = code_find_codeinfo_for_pc(rp->pc);
1092 topslot = TOP_IS_NORMAL;
1096 sp = (stackslot_t *) es->sp;
1098 /* in some cases the top stack slot is passed in REG_ITMP1 */
1100 if (rp->type == BBTYPE_EXH) {
1101 topslot = TOP_IS_IN_ITMP1;
1104 /* calculate base stack pointer */
1106 basesp = sp + code_get_stack_frame_size(code);
1108 /* create the source frame */
1110 frame = replace_new_sourceframe(ss);
1111 frame->method = rp->method;
1113 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1114 frame->type = replace_normalize_type_map[rp->type];
1116 frame->fromcode = code;
1118 /* read local variables */
1120 count = m->maxlocals;
1121 frame->javalocalcount = count;
1122 frame->javalocals = DMNEW(replace_val_t, count);
1123 frame->javalocaltype = DMNEW(u1, count);
1125 /* mark values as undefined */
1126 for (i=0; i<count; ++i) {
1127 #if !defined(NDEBUG)
1128 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1130 frame->javalocaltype[i] = TYPE_VOID;
1133 /* some entries in the intregs array are not meaningful */
1134 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1135 #if !defined(NDEBUG)
1136 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1138 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1140 #endif /* !defined(NDEBUG) */
1142 /* read javalocals */
1144 count = rp->regalloccount;
1147 while (count && (i = ra->index) >= 0) {
1148 assert(i < m->maxlocals);
1149 frame->javalocaltype[i] = ra->type;
1150 if (ra->type == TYPE_RET)
1151 frame->javalocals[i].i = ra->regoff;
1153 replace_read_value(es, sp, ra, frame->javalocals + i);
1158 /* read instance, if this is the first rplpoint */
1160 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1161 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1163 /* we are at the start of the method body, so if local 0 is set, */
1164 /* it is the instance. */
1165 if (frame->javalocaltype[0] == TYPE_ADR)
1166 frame->instance = frame->javalocals[0];
1171 md = rp->method->parseddesc;
1173 assert(md->paramcount >= 1);
1174 instra.type = TYPE_ADR;
1175 instra.regoff = md->params[0].regoff;
1176 if (md->params[0].inmemory) {
1177 instra.flags = INMEMORY;
1178 instra.regoff += (1 + code->stackframesize);
1183 replace_read_value(es, sp, &instra, &(frame->instance));
1186 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1188 /* read stack slots */
1190 frame->javastackdepth = count;
1191 frame->javastack = DMNEW(replace_val_t, count);
1192 frame->javastacktype = DMNEW(u1, count);
1194 #if !defined(NDEBUG)
1195 /* mark values as undefined */
1196 for (i=0; i<count; ++i) {
1197 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1198 frame->javastacktype[i] = TYPE_VOID;
1200 #endif /* !defined(NDEBUG) */
1204 /* the first stack slot is special in SBR and EXH blocks */
1206 if (topslot == TOP_IS_ON_STACK) {
1209 assert(ra->index == RPLALLOC_STACK);
1210 assert(ra->type == TYPE_ADR);
1211 frame->javastack[i].p = sp[-1];
1212 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1217 else if (topslot == TOP_IS_IN_ITMP1) {
1220 assert(ra->index == RPLALLOC_STACK);
1221 assert(ra->type == TYPE_ADR);
1222 frame->javastack[i].p = es->intregs[REG_ITMP1];
1223 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1228 else if (topslot == TOP_IS_VOID) {
1231 assert(ra->index == RPLALLOC_STACK);
1232 frame->javastack[i].l = 0;
1233 frame->javastacktype[i] = TYPE_VOID;
1239 /* read remaining stack slots */
1241 for (; count--; ra++) {
1242 if (ra->index == RPLALLOC_SYNC) {
1243 assert(rp->type == RPLPOINT_TYPE_INLINE);
1245 /* only read synchronization slots when traversing an inline point */
1248 sourceframe_t *calleeframe = frame->down;
1249 assert(calleeframe);
1250 assert(calleeframe->syncslotcount == 0);
1251 assert(calleeframe->syncslots == NULL);
1253 calleeframe->syncslotcount = 1;
1254 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1255 replace_read_value(es,sp,ra,calleeframe->syncslots);
1258 frame->javastackdepth--;
1262 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1264 /* do not read parameters of calls down the call chain */
1266 if (!topframe && ra->index == RPLALLOC_PARAM) {
1267 frame->javastackdepth--;
1270 if (ra->type == TYPE_RET)
1271 frame->javastack[i].i = ra->regoff;
1273 replace_read_value(es,sp,ra,frame->javastack + i);
1274 frame->javastacktype[i] = ra->type;
1281 /* replace_write_executionstate ************************************************
1283 Translate the given source state into an execution state.
1286 rp...............replacement point for which execution state should be
1288 es...............where to put the execution state
1289 ss...............the given source state
1292 *es..............the execution state derived from the source state
1294 *******************************************************************************/
1296 static void replace_write_executionstate(rplpoint *rp,
1297 executionstate_t *es,
1306 sourceframe_t *frame;
1309 stackslot_t *basesp;
1311 code = code_find_codeinfo_for_pc(rp->pc);
1313 topslot = TOP_IS_NORMAL;
1315 /* pop a source frame */
1319 ss->frames = frame->down;
1321 /* calculate stack pointer */
1323 sp = (stackslot_t *) es->sp;
1325 basesp = sp + code_get_stack_frame_size(code);
1327 /* in some cases the top stack slot is passed in REG_ITMP1 */
1329 if (rp->type == BBTYPE_EXH) {
1330 topslot = TOP_IS_IN_ITMP1;
1333 /* write javalocals */
1336 count = rp->regalloccount;
1338 while (count && (i = ra->index) >= 0) {
1339 assert(i < m->maxlocals);
1340 assert(i < frame->javalocalcount);
1341 assert(ra->type == frame->javalocaltype[i]);
1342 if (ra->type == TYPE_RET) {
1343 /* XXX assert that it matches this rplpoint */
1346 replace_write_value(es, sp, ra, frame->javalocals + i);
1351 /* write stack slots */
1355 /* the first stack slot is special in SBR and EXH blocks */
1357 if (topslot == TOP_IS_ON_STACK) {
1360 assert(ra->index == RPLALLOC_STACK);
1361 assert(i < frame->javastackdepth);
1362 assert(frame->javastacktype[i] == TYPE_ADR);
1363 sp[-1] = frame->javastack[i].p;
1368 else if (topslot == TOP_IS_IN_ITMP1) {
1371 assert(ra->index == RPLALLOC_STACK);
1372 assert(i < frame->javastackdepth);
1373 assert(frame->javastacktype[i] == TYPE_ADR);
1374 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1379 else if (topslot == TOP_IS_VOID) {
1382 assert(ra->index == RPLALLOC_STACK);
1383 assert(i < frame->javastackdepth);
1384 assert(frame->javastacktype[i] == TYPE_VOID);
1390 /* write remaining stack slots */
1392 for (; count--; ra++) {
1393 if (ra->index == RPLALLOC_SYNC) {
1394 assert(rp->type == RPLPOINT_TYPE_INLINE);
1396 /* only write synchronization slots when traversing an inline point */
1399 assert(frame->down);
1400 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1401 assert(frame->down->syncslots != NULL);
1403 replace_write_value(es,sp,ra,frame->down->syncslots);
1408 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1410 /* do not write parameters of calls down the call chain */
1412 if (!topframe && ra->index == RPLALLOC_PARAM) {
1416 assert(i < frame->javastackdepth);
1417 assert(ra->type == frame->javastacktype[i]);
1418 if (ra->type == TYPE_RET) {
1419 /* XXX assert that it matches this rplpoint */
1422 replace_write_value(es,sp,ra,frame->javastack + i);
1434 /* replace_pop_activation_record ***********************************************
1436 Peel a stack frame from the execution state.
1438 *** This function imitates the effects of the method epilog ***
1439 *** and returning from the method call. ***
1442 es...............execution state
1443 frame............source frame, receives synchronization slots
1446 *es..............the execution state after popping the stack frame
1448 *******************************************************************************/
1450 u1* replace_pop_activation_record(executionstate_t *es,
1451 sourceframe_t *frame)
1459 stackslot_t *basesp;
1465 /* read the return address */
1467 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1468 if (CODE_IS_LEAFMETHOD(es->code))
1469 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1472 ra = md_stacktrace_get_returnaddress(es->sp,
1473 SIZE_OF_STACKSLOT * es->code->stackframesize);
1475 DOLOG( printf("return address: %p\n", (void*)ra); );
1479 /* calculate the base of the stack frame */
1481 sp = (stackslot_t *) es->sp;
1482 basesp = sp + es->code->stackframesize;
1484 /* read slots used for synchronization */
1486 assert(frame->syncslotcount == 0);
1487 assert(frame->syncslots == NULL);
1488 count = code_get_sync_slot_count(es->code);
1489 frame->syncslotcount = count;
1490 frame->syncslots = DMNEW(replace_val_t, count);
1491 for (i=0; i<count; ++i) {
1492 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1495 /* restore return address, if part of frame */
1497 #if defined(REPLACE_RA_TOP_OF_FRAME)
1498 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1499 if (!CODE_IS_LEAFMETHOD(es->code))
1501 es->intregs[REPLACE_REG_RA] = *--basesp;
1502 #endif /* REPLACE_RA_TOP_OF_FRAME */
1504 #if defined(REPLACE_RA_LINKAGE_AREA)
1505 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1506 if (!CODE_IS_LEAFMETHOD(es->code))
1508 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1509 #endif /* REPLACE_RA_LINKAGE_AREA */
1511 /* restore saved int registers */
1514 for (i=0; i<es->code->savedintcount; ++i) {
1515 while (nregdescint[--reg] != REG_SAV)
1517 es->intregs[reg] = *--basesp;
1520 /* restore saved flt registers */
1524 for (i=0; i<es->code->savedfltcount; ++i) {
1525 while (nregdescfloat[--reg] != REG_SAV)
1527 basesp -= STACK_SLOTS_PER_FLOAT;
1528 es->fltregs[reg] = *(double*)basesp;
1531 /* adjust the stackpointer */
1533 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1535 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1536 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1539 /* Set the new pc. Subtract one so we do not hit the replacement point */
1540 /* of the instruction following the call, if there is one. */
1544 /* find the new codeinfo */
1546 pv = md_codegen_get_pv_from_pc(ra);
1548 DOLOG( printf("PV = %p\n", (void*) pv); );
1550 if (pv == NULL) /* XXX can this really happen? */
1553 code = *(codeinfo **)(pv + CodeinfoPointer);
1555 DOLOG( printf("CODE = %p\n", (void*) code); );
1557 /* return NULL if we reached native code */
1562 /* in debugging mode clobber non-saved registers */
1564 #if !defined(NDEBUG)
1566 for (i=0; i<INT_REG_CNT; ++i)
1567 if ((nregdescint[i] != REG_SAV)
1569 && (i != REPLACE_REG_RA)
1572 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1573 for (i=0; i<FLT_REG_CNT; ++i)
1574 if (nregdescfloat[i] != REG_SAV)
1575 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1576 #endif /* !defined(NDEBUG) */
1578 return (code) ? ra : NULL;
1582 /* replace_patch_method_pointer ************************************************
1584 Patch a method pointer (may be in code, data segment, vftbl, or interface
1588 mpp..............address of the method pointer to patch
1589 entrypoint.......the new entrypoint of the method
1590 kind.............kind of call to patch, used only for debugging
1592 *******************************************************************************/
1594 static void replace_patch_method_pointer(methodptr *mpp,
1595 methodptr entrypoint,
1598 #if !defined(NDEBUG)
1603 DOLOG( printf("patch method pointer from: %p to %p\n",
1604 (void*) *mpp, (void*)entrypoint); );
1606 #if !defined(NDEBUG)
1607 oldcode = *(codeinfo **)((u1*)(*mpp) + CodeinfoPointer);
1608 newcode = *(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer);
1610 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1611 method_println(oldcode->m);
1612 printf("\t with %p ", (void*) newcode);
1613 method_println(newcode->m); );
1615 assert(oldcode->m == newcode->m);
1618 /* write the new entrypoint */
1620 *mpp = (methodptr) entrypoint;
1624 /* replace_patch_class *********************************************************
1626 Patch a method in the given class.
1629 vftbl............vftbl of the class
1630 m................the method to patch
1631 oldentrypoint....the old entrypoint to replace
1632 entrypoint.......the new entrypoint
1634 *******************************************************************************/
1636 void replace_patch_class(vftbl_t *vftbl,
1645 /* patch the vftbl of the class */
1647 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1651 /* patch the interface tables */
1653 assert(oldentrypoint);
1655 for (i=0; i < vftbl->interfacetablelength; ++i) {
1656 mpp = vftbl->interfacetable[-i];
1657 mppend = mpp + vftbl->interfacevftbllength[i];
1658 for (; mpp != mppend; ++mpp)
1659 if (*mpp == oldentrypoint) {
1660 replace_patch_method_pointer(mpp, entrypoint, "interface");
1666 /* replace_patch_class_hierarchy ***********************************************
1668 Patch a method in all loaded classes.
1671 m................the method to patch
1672 oldentrypoint....the old entrypoint to replace
1673 entrypoint.......the new entrypoint
1675 *******************************************************************************/
1677 struct replace_patch_data_t {
1683 #define CODEINFO_OF_CODE(entrypoint) \
1684 (*(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer))
1686 #define METHOD_OF_CODE(entrypoint) \
1687 (CODEINFO_OF_CODE(entrypoint)->m)
1689 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1691 vftbl_t *vftbl = c->vftbl;
1694 && vftbl->vftbllength > pd->m->vftblindex
1695 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1696 && METHOD_OF_CODE(vftbl->table[pd->m->vftblindex]) == pd->m)
1698 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1702 void replace_patch_class_hierarchy(methodinfo *m,
1706 struct replace_patch_data_t pd;
1709 pd.oldentrypoint = oldentrypoint;
1710 pd.entrypoint = entrypoint;
1712 DOLOG_SHORT( printf("patching class hierarchy: ");
1713 method_println(m); );
1715 classcache_foreach_loaded_class(
1716 (classcache_foreach_functionptr_t) &replace_patch_callback,
1721 /* replace_patch_future_calls **************************************************
1723 Analyse a call site and depending on the kind of call patch the call, the
1724 virtual function table, or the interface table.
1727 ra...............return address pointing after the call site
1728 callerframe......source frame of the caller
1729 calleeframe......source frame of the callee, must have been mapped
1731 *******************************************************************************/
1733 void replace_patch_future_calls(u1 *ra,
1734 sourceframe_t *callerframe,
1735 sourceframe_t *calleeframe)
1738 methodptr entrypoint;
1739 methodptr oldentrypoint;
1742 codeinfo *calleecode;
1743 methodinfo *calleem;
1744 java_objectheader *obj;
1748 assert(callerframe->down == calleeframe);
1750 /* get the new codeinfo and the method that shall be entered */
1752 calleecode = calleeframe->tocode;
1755 calleem = calleeframe->method;
1756 assert(calleem == calleecode->m);
1758 entrypoint = (methodptr) calleecode->entrypoint;
1760 /* check if we are at an method entry rplpoint at the innermost frame */
1762 atentry = (calleeframe->down == NULL)
1763 && !(calleem->flags & ACC_STATIC)
1764 && (calleeframe->fromrp->id == 0); /* XXX */
1766 /* get the position to patch, in case it was a statically bound call */
1768 sfi.pv = callerframe->fromcode->entrypoint;
1769 patchpos = md_get_method_patch_address(ra, &sfi, NULL);
1771 if (patchpos == NULL) {
1772 /* the call was dispatched dynamically */
1774 /* we can only patch such calls if we are at the entry point */
1779 assert((calleem->flags & ACC_STATIC) == 0);
1781 oldentrypoint = calleeframe->fromcode->entrypoint;
1783 /* we need to know the instance */
1785 if (!calleeframe->instance.a) {
1786 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1787 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1793 obj = calleeframe->instance.a;
1796 assert(vftbl->class->vftbl == vftbl);
1798 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1800 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1803 /* the call was statically bound */
1805 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1810 /* replace_push_activation_record **********************************************
1812 Push a stack frame onto the execution state.
1814 *** This function imitates the effects of a call and the ***
1815 *** method prolog of the callee. ***
1818 es...............execution state
1819 rpcall...........the replacement point at the call site
1820 callerframe......source frame of the caller, or NULL for creating the
1822 calleeframe......source frame of the callee, must have been mapped
1825 *es..............the execution state after pushing the stack frame
1827 *******************************************************************************/
1829 void replace_push_activation_record(executionstate_t *es,
1831 sourceframe_t *callerframe,
1832 sourceframe_t *calleeframe)
1837 stackslot_t *basesp;
1840 codeinfo *calleecode;
1843 assert(!rpcall || callerframe);
1844 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1845 assert(!rpcall || rpcall == callerframe->torp);
1846 assert(calleeframe);
1847 assert(!callerframe || calleeframe == callerframe->down);
1849 /* the compilation unit we are entering */
1851 calleecode = calleeframe->tocode;
1854 /* calculate the return address */
1857 ra = rpcall->pc + rpcall->callsize;
1859 ra = es->pc + 1 /* XXX this is ugly */;
1861 /* write the return address */
1863 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1864 es->sp -= SIZE_OF_STACKSLOT;
1866 *((stackslot_t *)es->sp) = (stackslot_t) ra;
1867 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1869 #if defined(REPLACE_REG_RA)
1870 es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1873 /* we move into a new code unit */
1875 es->code = calleecode;
1877 /* set the new pc XXX not needed? */
1879 es->pc = calleecode->entrypoint;
1881 /* build the stackframe */
1883 DOLOG( printf("building stackframe of %d words at %p\n",
1884 calleecode->stackframesize, (void*)es->sp); );
1886 sp = (stackslot_t *) es->sp;
1889 sp -= calleecode->stackframesize;
1892 /* in debug mode, invalidate stack frame first */
1894 /* XXX may not invalidate linkage area used by native code! */
1895 #if !defined(NDEBUG) && 0
1896 for (i=0; i<(basesp - sp); ++i) {
1897 sp[i] = 0xdeaddeadU;
1901 /* save the return address register */
1903 #if defined(REPLACE_RA_TOP_OF_FRAME)
1904 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1905 if (!CODE_IS_LEAFMETHOD(calleecode))
1907 *--basesp = (ptrint) ra;
1908 #endif /* REPLACE_RA_TOP_OF_FRAME */
1910 #if defined(REPLACE_RA_LINKAGE_AREA)
1911 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1912 if (!CODE_IS_LEAFMETHOD(calleecode))
1914 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1915 #endif /* REPLACE_RA_LINKAGE_AREA */
1917 /* save int registers */
1920 for (i=0; i<calleecode->savedintcount; ++i) {
1921 while (nregdescint[--reg] != REG_SAV)
1923 *--basesp = es->intregs[reg];
1925 /* XXX may not clobber saved regs used by native code! */
1926 #if !defined(NDEBUG) && 0
1927 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1931 /* save flt registers */
1935 for (i=0; i<calleecode->savedfltcount; ++i) {
1936 while (nregdescfloat[--reg] != REG_SAV)
1938 basesp -= STACK_SLOTS_PER_FLOAT;
1939 *(double*)basesp = es->fltregs[reg];
1941 /* XXX may not clobber saved regs used by native code! */
1942 #if !defined(NDEBUG) && 0
1943 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1947 /* write slots used for synchronization */
1949 count = code_get_sync_slot_count(calleecode);
1950 assert(count == calleeframe->syncslotcount);
1951 for (i=0; i<count; ++i) {
1952 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
1957 es->pv = calleecode->entrypoint;
1959 /* redirect future invocations */
1961 if (callerframe && rpcall) {
1962 #if defined(REPLACE_PATCH_ALL)
1963 if (rpcall->type == callerframe->fromrp->type)
1965 if (rpcall == callerframe->fromrp)
1967 replace_patch_future_calls(ra, callerframe, calleeframe);
1972 /* replace_find_replacement_point **********************************************
1974 Find the replacement point in the given code corresponding to the
1975 position given in the source frame.
1978 code.............the codeinfo in which to search the rplpoint
1979 frame............the source frame defining the position to look for
1980 parent...........parent replacement point to match
1983 the replacement point
1985 *******************************************************************************/
1987 rplpoint * replace_find_replacement_point(codeinfo *code,
1988 sourceframe_t *frame,
2001 DOLOG( printf("searching replacement point for:\n");
2002 replace_source_frame_println(frame); );
2006 DOLOG( printf("code = %p\n", (void*)code); );
2008 rp = code->rplpoints;
2009 i = code->rplpointcount;
2011 if (rp->id == frame->id && rp->method == frame->method
2012 && rp->parent == parent
2013 && replace_normalize_type_map[rp->type] == frame->type)
2015 /* check if returnAddresses match */
2016 /* XXX optimize: only do this if JSRs in method */
2017 DOLOG( printf("checking match for:");
2018 replace_replacement_point_println(rp, 1); fflush(stdout); );
2021 for (j = rp->regalloccount; j--; ++ra) {
2022 if (ra->type == TYPE_RET) {
2023 if (ra->index == RPLALLOC_STACK) {
2024 assert(stacki < frame->javastackdepth);
2025 if (frame->javastack[stacki].i != ra->regoff)
2030 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2031 if (frame->javalocals[ra->index].i != ra->regoff)
2044 #if !defined(NDEBUG)
2045 printf("candidate replacement points were:\n");
2046 rp = code->rplpoints;
2047 i = code->rplpointcount;
2049 replace_replacement_point_println(rp, 1);
2053 vm_abort("no matching replacement point found");
2054 return NULL; /* NOT REACHED */
2058 /* replace_find_replacement_point_for_pc ***************************************
2060 Find the nearest replacement point at or before the given PC.
2063 code.............compilation unit the PC is in
2064 pc...............the machine code PC
2067 the replacement point found, or
2068 NULL if no replacement point was found
2070 *******************************************************************************/
2072 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2078 DOLOG( printf("searching for rp in %p ", (void*)code);
2079 method_println(code->m); );
2083 rp = code->rplpoints;
2084 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2085 DOLOG( replace_replacement_point_println(rp, 2); );
2094 /* replace_pop_native_frame ****************************************************
2096 Unroll a native frame in the execution state and create a source frame
2100 es...............current execution state
2101 ss...............the current source state
2102 sfi..............stackframeinfo for the native frame
2105 es...............execution state after unrolling the native frame
2106 ss...............gets the added native source frame
2108 *******************************************************************************/
2110 static void replace_pop_native_frame(executionstate_t *es,
2112 stackframeinfo *sfi)
2114 sourceframe_t *frame;
2120 frame = replace_new_sourceframe(ss);
2124 /* remember pc and size of native frame */
2126 frame->nativepc = es->pc;
2127 frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2128 assert(frame->nativeframesize >= 0);
2130 /* remember values of saved registers */
2133 for (i=0; i<INT_REG_CNT; ++i) {
2134 if (nregdescint[i] == REG_SAV)
2135 frame->nativesavint[j++] = es->intregs[i];
2139 for (i=0; i<FLT_REG_CNT; ++i) {
2140 if (nregdescfloat[i] == REG_SAV)
2141 frame->nativesavflt[j++] = es->fltregs[i];
2144 /* restore saved registers */
2146 #if defined(ENABLE_GC_CACAO)
2148 for (i=0; i<INT_REG_CNT; ++i) {
2149 if (nregdescint[i] == REG_SAV)
2150 es->intregs[i] = sfi->intregs[j++];
2153 /* XXX we don't have them, yet, in the sfi, so clear them */
2155 for (i=0; i<INT_REG_CNT; ++i) {
2156 if (nregdescint[i] == REG_SAV)
2161 /* XXX we don't have float registers in the sfi, so clear them */
2163 for (i=0; i<FLT_REG_CNT; ++i) {
2164 if (nregdescfloat[i] == REG_SAV)
2165 es->fltregs[i] = 0.0;
2168 /* restore pv, pc, and sp */
2170 if (sfi->pv == NULL) {
2171 /* frame of a native function call */
2172 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2177 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2180 /* find the new codeinfo */
2182 DOLOG( printf("PV = %p\n", (void*) es->pv); );
2184 assert(es->pv != NULL);
2186 code = *(codeinfo **)(es->pv + CodeinfoPointer);
2188 DOLOG( printf("CODE = %p\n", (void*) code); );
2194 /* replace_push_native_frame ***************************************************
2196 Rebuild a native frame onto the execution state and remove its source frame.
2198 Note: The native frame is "rebuild" by setting fields like PC and stack
2199 pointer in the execution state accordingly. Values in the
2200 stackframeinfo may be modified, but the actual stack frame of the
2201 native code is not touched.
2204 es...............current execution state
2205 ss...............the current source state
2208 es...............execution state after re-rolling the native frame
2209 ss...............the native source frame is removed
2211 *******************************************************************************/
2213 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2215 sourceframe_t *frame;
2221 DOLOG( printf("pushing native frame\n"); );
2223 /* remove the frame from the source state */
2227 assert(REPLACE_IS_NATIVE_FRAME(frame));
2229 ss->frames = frame->down;
2231 /* assert that the native frame has not moved */
2233 assert(es->sp == frame->sfi->sp);
2235 /* update saved registers in the stackframeinfo */
2237 #if defined(ENABLE_GC_CACAO)
2239 for (i=0; i<INT_REG_CNT; ++i) {
2240 if (nregdescint[i] == REG_SAV)
2241 frame->sfi->intregs[j++] = es->intregs[i];
2244 /* XXX leave float registers untouched here */
2247 /* restore saved registers */
2250 for (i=0; i<INT_REG_CNT; ++i) {
2251 if (nregdescint[i] == REG_SAV)
2252 es->intregs[i] = frame->nativesavint[j++];
2256 for (i=0; i<FLT_REG_CNT; ++i) {
2257 if (nregdescfloat[i] == REG_SAV)
2258 es->fltregs[i] = frame->nativesavflt[j++];
2261 /* skip the native frame on the machine stack */
2263 es->sp -= frame->nativeframesize;
2265 /* set the pc the next frame must return to */
2267 es->pc = frame->nativepc;
2271 /* replace_recover_source_state ************************************************
2273 Recover the source state from the given replacement point and execution
2277 rp...............replacement point that has been reached, if any
2278 sfi..............stackframeinfo, if called from native code
2279 es...............execution state at the replacement point rp
2284 *******************************************************************************/
2286 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2287 stackframeinfo *sfi,
2288 executionstate_t *es)
2293 #if defined(REPLACE_STATISTICS)
2297 /* create the source frame structure in dump memory */
2299 ss = DNEW(sourcestate_t);
2302 /* each iteration of the loop recovers one source frame */
2309 DOLOG( replace_executionstate_println(es); );
2311 /* if we are not at a replacement point, it is a native frame */
2314 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2317 replace_pop_native_frame(es, ss, sfi);
2320 if (es->code == NULL)
2323 goto after_machine_frame;
2326 /* read the values for this source frame from the execution state */
2328 DOLOG( printf("recovering source state for%s:\n",
2329 (ss->frames == NULL) ? " TOPFRAME" : "");
2330 replace_replacement_point_println(rp, 1); );
2332 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2334 #if defined(REPLACE_STATISTICS)
2335 REPLACE_COUNT(stat_frames);
2337 replace_statistics_source_frame(ss->frames);
2340 /* in locked areas (below native frames), identity map the frame */
2343 ss->frames->torp = ss->frames->fromrp;
2344 ss->frames->tocode = ss->frames->fromcode;
2347 /* unroll to the next (outer) frame */
2350 /* this frame is in inlined code */
2352 DOLOG( printf("INLINED!\n"); );
2356 assert(rp->type == RPLPOINT_TYPE_INLINE);
2357 REPLACE_COUNT(stat_unroll_inline);
2360 /* this frame had been called at machine-level. pop it. */
2362 DOLOG( printf("UNWIND\n"); );
2364 ra = replace_pop_activation_record(es, ss->frames);
2366 DOLOG( printf("REACHED NATIVE CODE\n"); );
2370 break; /* XXX remove to activate native frames */
2374 /* find the replacement point at the call site */
2376 after_machine_frame:
2377 rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2380 vm_abort("could not find replacement point while unrolling call");
2382 DOLOG( printf("found replacement point.\n");
2383 replace_replacement_point_println(rp, 1); );
2385 assert(rp->type == RPLPOINT_TYPE_CALL);
2386 REPLACE_COUNT(stat_unroll_call);
2388 } /* end loop over source frames */
2390 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2396 /* replace_map_source_state ****************************************************
2398 Map each source frame in the given source state to a target replacement
2399 point and compilation unit. If no valid code is available for a source
2400 frame, it is (re)compiled.
2403 ss...............the source state
2406 ss...............the source state, modified: The `torp` and `tocode`
2407 fields of each source frame are set.
2410 true.............everything went ok
2411 false............an exception has been thrown
2413 *******************************************************************************/
2415 static bool replace_map_source_state(sourcestate_t *ss)
2417 sourceframe_t *frame;
2420 rplpoint *parent; /* parent of inlined rplpoint */
2421 #if defined(REPLACE_STATISTICS)
2428 /* iterate over the source frames from outermost to innermost */
2430 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2432 /* XXX skip native frames */
2434 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2439 /* map frames which are not already mapped */
2441 if (frame->tocode) {
2442 code = frame->tocode;
2447 assert(frame->torp == NULL);
2449 if (parent == NULL) {
2450 /* find code for this frame */
2452 #if defined(REPLACE_STATISTICS)
2453 oldcode = frame->method->code;
2455 /* request optimization of hot methods and their callers */
2457 if (frame->method->hitcountdown < 0
2458 || (frame->down && frame->down->method->hitcountdown < 0))
2459 jit_request_optimization(frame->method);
2461 code = jit_get_current_code(frame->method);
2464 return false; /* exception */
2466 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2471 /* map this frame */
2473 rp = replace_find_replacement_point(code, frame, parent);
2475 frame->tocode = code;
2479 if (rp->type == RPLPOINT_TYPE_CALL) {
2492 /* replace_map_source_state_identity *******************************************
2494 Map each source frame in the given source state to the same replacement
2495 point and compilation unit it was derived from. This is mainly used for
2499 ss...............the source state
2502 ss...............the source state, modified: The `torp` and `tocode`
2503 fields of each source frame are set.
2505 *******************************************************************************/
2507 #if defined(ENABLE_GC_CACAO)
2508 static void replace_map_source_state_identity(sourcestate_t *ss)
2510 sourceframe_t *frame;
2512 /* iterate over the source frames from outermost to innermost */
2514 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2516 /* skip native frames */
2518 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2522 /* map frames using the identity mapping */
2524 if (frame->tocode) {
2525 assert(frame->tocode == frame->fromcode);
2526 assert(frame->torp == frame->fromrp);
2528 assert(frame->tocode == NULL);
2529 assert(frame->torp == NULL);
2530 frame->tocode = frame->fromcode;
2531 frame->torp = frame->fromrp;
2538 /* replace_build_execution_state_intern ****************************************
2540 Build an execution state for the given (mapped) source state.
2542 !!! CAUTION: This function rewrites the machine stack !!!
2544 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2547 ss...............the source state. Must have been mapped by
2548 replace_map_source_state before.
2549 es...............the base execution state on which to build
2552 *es..............the new execution state
2554 *******************************************************************************/
2556 void replace_build_execution_state_intern(sourcestate_t *ss,
2557 executionstate_t *es)
2560 sourceframe_t *prevframe;
2567 while (ss->frames) {
2569 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2570 prevframe = ss->frames;
2571 replace_push_native_frame(es, ss);
2577 if (parent == NULL) {
2578 /* create a machine-level stack frame */
2580 DOLOG( printf("pushing activation record for:\n");
2581 if (rp) replace_replacement_point_println(rp, 1);
2582 else printf("\tfirst frame\n"); );
2584 replace_push_activation_record(es, rp, prevframe, ss->frames);
2586 DOLOG( replace_executionstate_println(es); );
2589 rp = ss->frames->torp;
2592 DOLOG( printf("creating execution state for%s:\n",
2593 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2594 replace_replacement_point_println(ss->frames->fromrp, 1);
2595 replace_replacement_point_println(rp, 1); );
2597 es->code = ss->frames->tocode;
2598 prevframe = ss->frames;
2599 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2601 DOLOG( replace_executionstate_println(es); );
2603 if (rp->type == RPLPOINT_TYPE_CALL) {
2614 /* replace_build_execution_state ***********************************************
2616 This function contains the final phase of replacement. It builds the new
2617 execution state, releases dump memory, and returns to the calling
2618 assembler function which finishes replacement.
2620 NOTE: This function is called from asm_replacement_in, with the stack
2621 pointer at the start of the safe stack area.
2623 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2625 CAUTION: This function and its children must not use a lot of stack!
2626 There are only REPLACE_SAFESTACK_SIZE bytes of C stack
2630 st...............the safestack contained the necessary data
2632 *******************************************************************************/
2634 void replace_build_execution_state(replace_safestack_t *st)
2636 replace_build_execution_state_intern(st->ss, &(st->es));
2638 DOLOG( replace_executionstate_println(&(st->es)); );
2640 /* release dump area */
2642 dump_release(st->dumpsize);
2644 /* new code is entered after returning */
2646 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2650 /* replace_alloc_safestack *****************************************************
2652 Allocate a safe stack area to use during the final phase of replacement.
2653 The returned area is not initialized. This must be done by the caller.
2656 a newly allocated replace_safestack_t *
2658 *******************************************************************************/
2660 static replace_safestack_t *replace_alloc_safestack()
2663 replace_safestack_t *st;
2665 mem = MNEW(u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2667 st = (replace_safestack_t *) ((ptrint)(mem + REPLACE_STACK_ALIGNMENT - 1)
2668 & ~(REPLACE_STACK_ALIGNMENT - 1));
2670 #if !defined(NDEBUG)
2671 memset(st, 0xa5, sizeof(replace_safestack_t));
2680 /* replace_free_safestack ******************************************************
2682 Free the given safestack structure, making a copy of the contained
2683 execution state before freeing it.
2685 NOTE: This function is called from asm_replacement_in.
2688 st...............the safestack to free
2689 tmpes............where to copy the execution state to
2692 *tmpes...........receives a copy of st->es
2694 *******************************************************************************/
2696 void replace_free_safestack(replace_safestack_t *st, executionstate_t *tmpes)
2700 /* copy the executionstate_t to the temporary location */
2704 /* get the memory address to free */
2708 /* destroy memory (in debug mode) */
2710 #if !defined(NDEBUG)
2711 memset(st, 0xa5, sizeof(replace_safestack_t));
2714 /* free the safe stack struct */
2716 MFREE(mem, u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2720 /* replace_me ******************************************************************
2722 This function is called by asm_replacement_out when a thread reaches
2723 a replacement point. `replace_me` must map the execution state to the
2724 target replacement point and let execution continue there.
2726 This function never returns!
2729 rp...............replacement point that has been reached
2730 es...............execution state read by asm_replacement_out
2732 *******************************************************************************/
2734 void replace_me(rplpoint *rp, executionstate_t *es)
2736 stackframeinfo *sfi;
2738 sourceframe_t *frame;
2741 replace_safestack_t *safestack;
2742 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2743 threadobject *thread;
2747 es->code = code_find_codeinfo_for_pc(rp->pc);
2749 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2750 stat_replacements, (void*)THREADOBJECT,
2752 method_println(es->code->m); );
2754 DOLOG( replace_replacement_point_println(rp, 1);
2755 replace_executionstate_println(es); );
2757 REPLACE_COUNT(stat_replacements);
2759 /* mark start of dump memory area */
2761 dumpsize = dump_size();
2763 /* get the stackframeinfo for the current thread */
2765 sfi = STACKFRAMEINFO;
2767 /* recover source state */
2769 ss = replace_recover_source_state(rp, sfi, es);
2771 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2772 /* if there is a collection pending, we assume the replacement point should
2773 suspend this thread */
2777 thread = THREADOBJECT;
2779 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2781 /* map the sourcestate using the identity mapping */
2782 replace_map_source_state_identity(ss);
2784 /* since we enter the same method again, we turn off rps now */
2785 /* XXX michi: can we really do this? what if the rp was active before
2786 we activated it for the gc? */
2789 frame = frame->down;
2790 replace_deactivate_replacement_points(frame->tocode);
2792 /* remember executionstate and sourcestate for this thread */
2793 GC_EXECUTIONSTATE = es;
2794 GC_SOURCESTATE = ss;
2796 /* really suspend this thread now (PC = 0) */
2797 threads_suspend_ack(NULL, NULL);
2799 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2802 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2804 /* map the source state */
2806 if (!replace_map_source_state(ss))
2807 vm_abort("exception during method replacement");
2809 DOLOG( replace_sourcestate_println(ss); );
2811 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2813 /* avoid infinite loops by self-replacement */
2817 frame = frame->down;
2819 if (frame->torp == origrp) {
2821 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2823 replace_deactivate_replacement_points(frame->tocode);
2826 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2830 /* write execution state of new code */
2832 DOLOG( replace_executionstate_println(es); );
2834 /* allocate a safe stack area and copy all needed data there */
2836 safestack = replace_alloc_safestack();
2838 safestack->es = *es;
2840 safestack->dumpsize = dumpsize;
2842 /* call the assembler code for the last phase of replacement */
2844 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
2845 asm_replacement_in(&(safestack->es), safestack);
2848 abort(); /* NOT REACHED */
2852 /******************************************************************************/
2853 /* NOTE: Stuff specific to the exact GC is below. */
2854 /******************************************************************************/
2856 #if defined(ENABLE_GC_CACAO)
2857 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
2859 stackframeinfo *sfi;
2860 executionstate_t *es;
2863 /* get the stackframeinfo of this thread */
2864 assert(thread == THREADOBJECT);
2865 sfi = STACKFRAMEINFO;
2867 /* create the execution state */
2868 es = DNEW(executionstate_t);
2871 es->pv = 0; /* since we are in a native, PV is invalid! */
2872 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
2874 /* we assume we are in a native (no replacement point)! */
2875 ss = replace_recover_source_state(NULL, sfi, es);
2877 /* map the sourcestate using the identity mapping */
2878 replace_map_source_state_identity(ss);
2880 /* remember executionstate and sourcestate for this thread */
2881 GC_EXECUTIONSTATE = es;
2882 GC_SOURCESTATE = ss;
2887 /******************************************************************************/
2888 /* NOTE: No important code below. */
2889 /******************************************************************************/
2892 /* statistics *****************************************************************/
2894 #if defined(REPLACE_STATISTICS)
2895 static void print_freq(FILE *file,int *array,int limit)
2900 for (i=0; i<limit; ++i)
2902 sum += array[limit];
2903 for (i=0; i<limit; ++i) {
2905 fprintf(file," %3d: %8d (cum %3d%%)\n",
2906 i, array[i], (sum) ? ((100*cum)/sum) : 0);
2908 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
2910 #endif /* defined(REPLACE_STATISTICS) */
2913 #if defined(REPLACE_STATISTICS)
2915 #define REPLACE_PRINT_DIST(name, array) \
2916 printf(" " name " distribution:\n"); \
2917 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
2919 void replace_print_statistics(void)
2921 printf("replacement statistics:\n");
2922 printf(" # of replacements: %d\n", stat_replacements);
2923 printf(" # of frames: %d\n", stat_frames);
2924 printf(" # of recompilations: %d\n", stat_recompile);
2925 printf(" patched static calls:%d\n", stat_staticpatch);
2926 printf(" unrolled inlines: %d\n", stat_unroll_inline);
2927 printf(" unrolled calls: %d\n", stat_unroll_call);
2928 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
2929 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
2930 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
2931 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
2932 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
2933 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
2934 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
2935 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
2936 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
2937 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
2939 printf(" # of methods: %d\n", stat_methods);
2940 printf(" # of replacement points: %d\n", stat_rploints);
2941 printf(" # of regallocs: %d\n", stat_regallocs);
2942 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
2943 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
2944 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
2948 #endif /* defined(REPLACE_STATISTICS) */
2951 #if defined(REPLACE_STATISTICS)
2952 static void replace_statistics_source_frame(sourceframe_t *frame)
2961 for (i=0; i<frame->javalocalcount; ++i) {
2962 switch (frame->javalocaltype[i]) {
2963 case TYPE_ADR: adr++; break;
2964 case TYPE_RET: ret++; break;
2965 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
2966 case TYPE_VOID: vd++; break;
2971 REPLACE_COUNT_DIST(stat_dist_locals, n);
2972 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
2973 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
2974 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
2975 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
2976 adr = ret = prim = n = 0;
2977 for (i=0; i<frame->javastackdepth; ++i) {
2978 switch (frame->javastacktype[i]) {
2979 case TYPE_ADR: adr++; break;
2980 case TYPE_RET: ret++; break;
2981 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
2985 REPLACE_COUNT_DIST(stat_dist_stack, n);
2986 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
2987 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
2988 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
2990 #endif /* defined(REPLACE_STATISTICS) */
2993 /* debugging helpers **********************************************************/
2995 /* replace_replacement_point_println *******************************************
2997 Print replacement point info.
3000 rp...............the replacement point to print
3002 *******************************************************************************/
3004 #if !defined(NDEBUG)
3006 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3008 static char *replace_type_str[] = {
3018 void replace_replacement_point_println(rplpoint *rp, int depth)
3024 printf("(rplpoint *)NULL\n");
3028 for (j=0; j<depth; ++j)
3031 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3032 rp->id, (void*)rp,rp->pc,rp->callsize,
3033 replace_type_str[rp->type]);
3034 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3036 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3037 printf(" COUNTDOWN");
3038 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3040 printf(" parent:%p\n", (void*)rp->parent);
3041 for (j=0; j<depth; ++j)
3043 printf("ra:%d = [", rp->regalloccount);
3045 for (j=0; j<rp->regalloccount; ++j) {
3048 index = rp->regalloc[j].index;
3050 case RPLALLOC_STACK: printf("S"); break;
3051 case RPLALLOC_PARAM: printf("P"); break;
3052 case RPLALLOC_SYNC : printf("Y"); break;
3053 default: printf("%d", index);
3055 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3056 if (rp->regalloc[j].type == TYPE_RET) {
3057 printf("ret(L%03d)", rp->regalloc[j].regoff);
3060 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3065 for (j=0; j<depth; ++j)
3068 method_print(rp->method);
3072 #endif /* !defined(NDEBUG) */
3075 /* replace_show_replacement_points *********************************************
3077 Print replacement point info.
3080 code.............codeinfo whose replacement points should be printed.
3082 *******************************************************************************/
3084 #if !defined(NDEBUG)
3085 void replace_show_replacement_points(codeinfo *code)
3093 printf("(codeinfo *)NULL\n");
3097 printf("\treplacement points: %d\n",code->rplpointcount);
3099 printf("\ttotal allocations : %d\n",code->regalloccount);
3100 printf("\tsaved int regs : %d\n",code->savedintcount);
3101 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3102 printf("\tmemuse : %d\n",code->memuse);
3106 for (i=0; i<code->rplpointcount; ++i) {
3107 rp = code->rplpoints + i;
3110 parent = rp->parent;
3113 parent = parent->parent;
3115 replace_replacement_point_println(rp, depth);
3121 /* replace_executionstate_println **********************************************
3123 Print execution state
3126 es...............the execution state to print
3128 *******************************************************************************/
3130 #if !defined(NDEBUG)
3131 void replace_executionstate_println(executionstate_t *es)
3139 printf("(executionstate_t *)NULL\n");
3143 printf("executionstate_t:\n");
3144 printf("\tpc = %p",(void*)es->pc);
3145 printf(" sp = %p",(void*)es->sp);
3146 printf(" pv = %p\n",(void*)es->pv);
3147 #if defined(ENABLE_DISASSEMBLER)
3148 for (i=0; i<INT_REG_CNT; ++i) {
3153 #if SIZEOF_VOID_P == 8
3154 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3156 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3161 for (i=0; i<FLT_REG_CNT; ++i) {
3166 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3172 sp = (stackslot_t *) es->sp;
3177 methoddesc *md = es->code->m->parseddesc;
3178 slots = code_get_stack_frame_size(es->code);
3179 extraslots = 1 + md->memuse;
3186 printf("\tstack slots(+%d) at sp:", extraslots);
3187 for (i=0; i<slots+extraslots; ++i) {
3190 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3191 #ifdef HAS_4BYTE_STACKSLOT
3192 printf("%08lx",(unsigned long)*sp++);
3194 printf("%016llx",(unsigned long long)*sp++);
3196 printf("%c", (i >= slots) ? ')' : ' ');
3201 printf("\tcode: %p", (void*)es->code);
3202 if (es->code != NULL) {
3203 printf(" stackframesize=%d ", es->code->stackframesize);
3204 method_print(es->code->m);
3212 #if !defined(NDEBUG)
3213 static void java_value_print(s4 type, replace_val_t value)
3215 java_objectheader *obj;
3218 printf("%016llx",(unsigned long long) value.l);
3220 if (type < 0 || type > TYPE_RET)
3221 printf(" <INVALID TYPE:%d>", type);
3223 printf(" %s", show_jit_type_names[type]);
3225 if (type == TYPE_ADR && value.a != NULL) {
3228 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3230 if (obj->vftbl->class == class_java_lang_String) {
3232 u = javastring_toutf(obj, false);
3233 utf_display_printable_ascii(u);
3237 else if (type == TYPE_INT) {
3238 printf(" %ld", (long) value.i);
3240 else if (type == TYPE_LNG) {
3241 printf(" %lld", (long long) value.l);
3243 else if (type == TYPE_FLT) {
3244 printf(" %f", value.f);
3246 else if (type == TYPE_DBL) {
3247 printf(" %f", value.d);
3250 #endif /* !defined(NDEBUG) */
3253 #if !defined(NDEBUG)
3254 void replace_source_frame_println(sourceframe_t *frame)
3259 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3260 printf("\tNATIVE\n");
3261 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3262 printf("\tnativepc: %p\n", frame->nativepc);
3263 printf("\tframesize: %d\n", frame->nativeframesize);
3266 for (i=0; i<INT_REG_CNT; ++i) {
3267 if (nregdescint[i] == REG_SAV)
3268 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3272 for (i=0; i<FLT_REG_CNT; ++i) {
3273 if (nregdescfloat[i] == REG_SAV)
3274 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3282 method_println(frame->method);
3283 printf("\tid: %d\n", frame->id);
3284 printf("\ttype: %s\n", replace_type_str[frame->type]);
3287 if (frame->instance.a) {
3288 printf("\tinstance: ");
3289 java_value_print(TYPE_ADR, frame->instance);
3293 if (frame->javalocalcount) {
3294 printf("\tlocals (%d):\n",frame->javalocalcount);
3295 for (i=0; i<frame->javalocalcount; ++i) {
3296 t = frame->javalocaltype[i];
3297 if (t == TYPE_VOID) {
3298 printf("\tlocal[ %2d] = void\n",i);
3301 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3302 java_value_print(t, frame->javalocals[i]);
3309 if (frame->javastackdepth) {
3310 printf("\tstack (depth %d):\n",frame->javastackdepth);
3311 for (i=0; i<frame->javastackdepth; ++i) {
3312 t = frame->javastacktype[i];
3313 if (t == TYPE_VOID) {
3314 printf("\tstack[%2d] = void", i);
3317 printf("\tstack[%2d] = ",i);
3318 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3325 if (frame->syncslotcount) {
3326 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3327 for (i=0; i<frame->syncslotcount; ++i) {
3328 printf("\tslot[%2d] = ",i);
3329 #ifdef HAS_4BYTE_STACKSLOT
3330 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3332 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3338 if (frame->fromcode) {
3339 printf("\tfrom %p ", (void*)frame->fromcode);
3340 method_println(frame->fromcode->m);
3342 if (frame->tocode) {
3343 printf("\tto %p ", (void*)frame->tocode);
3344 method_println(frame->tocode->m);
3347 if (frame->fromrp) {
3348 printf("\tfrom replacement point:\n");
3349 replace_replacement_point_println(frame->fromrp, 2);
3352 printf("\tto replacement point:\n");
3353 replace_replacement_point_println(frame->torp, 2);
3358 #endif /* !defined(NDEBUG) */
3361 /* replace_sourcestate_println *************************************************
3366 ss...............the source state to print
3368 *******************************************************************************/
3370 #if !defined(NDEBUG)
3371 void replace_sourcestate_println(sourcestate_t *ss)
3374 sourceframe_t *frame;
3377 printf("(sourcestate_t *)NULL\n");
3381 printf("sourcestate_t:\n");
3383 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3384 printf(" frame %d:\n", i);
3385 replace_source_frame_println(frame);
3391 /* replace_sourcestate_println_short *******************************************
3393 Print a compact representation of the given source state.
3396 ss...............the source state to print
3398 *******************************************************************************/
3400 #if !defined(NDEBUG)
3401 void replace_sourcestate_println_short(sourcestate_t *ss)
3403 sourceframe_t *frame;
3405 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3408 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3409 printf("NATIVE (pc %p size %d) ",
3410 (void*)frame->nativepc, frame->nativeframesize);
3411 replace_stackframeinfo_println(frame->sfi);
3416 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3419 printf("%s", replace_type_str[frame->fromrp->type]);
3421 if (frame->torp && frame->torp->type != frame->fromrp->type)
3422 printf("->%s", replace_type_str[frame->torp->type]);
3424 if (frame->tocode != frame->fromcode)
3425 printf(" (%p->%p/%d) ",
3426 (void*) frame->fromcode, (void*) frame->tocode,
3429 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3431 method_println(frame->method);
3436 #if !defined(NDEBUG)
3437 static void replace_stackframeinfo_println(stackframeinfo *sfi)
3439 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3440 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3441 (void*)sfi->ra, (void*)sfi->xpc);
3444 method_println(sfi->method);
3451 * These are local overrides for various environment variables in Emacs.
3452 * Please do not remove this and leave it at the end of the file, where
3453 * Emacs will automagically detect them.
3454 * ---------------------------------------------------------------------
3457 * indent-tabs-mode: t
3461 * vim:noexpandtab:sw=4:ts=4: