1 /* vm/jit/replace.c - on-stack replacement of methods
3 Copyright (C) 1996-2005, 2006 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
25 Contact: cacao@cacaojvm.org
27 Authors: Edwin Steiner
41 #if defined(ENABLE_GC_CACAO)
42 # include "mm/cacao-gc/gc.h"
45 #include "mm/memory.h"
46 #include "toolbox/logging.h"
47 #include "vm/stringlocal.h"
48 #include "vm/jit/abi.h"
49 #include "vm/jit/jit.h"
50 #include "vm/jit/replace.h"
51 #include "vm/jit/stack.h"
52 #include "vm/jit/asmpart.h"
53 #include "vm/jit/disass.h"
54 #include "vm/jit/show.h"
55 #include "vm/jit/methodheader.h"
56 #include "vm/jit/md.h"
57 #include "vmcore/options.h"
58 #include "vmcore/classcache.h"
60 #include "native/include/java_lang_String.h"
62 #define REPLACE_PATCH_DYNAMIC_CALL
63 /*#define REPLACE_PATCH_ALL*/
66 /*** architecture-dependent configuration *************************************/
68 /* first unset the macros (default) */
69 #undef REPLACE_RA_BETWEEN_FRAMES
70 #undef REPLACE_RA_TOP_OF_FRAME
71 #undef REPLACE_RA_LINKAGE_AREA
72 #undef REPLACE_LEAFMETHODS_RA_REGISTER
76 #if defined(__I386__) || defined(__X86_64__)
77 #define REPLACE_RA_BETWEEN_FRAMES
79 #elif defined(__ALPHA__)
80 #define REPLACE_RA_TOP_OF_FRAME
81 #define REPLACE_LEAFMETHODS_RA_REGISTER
82 #define REPLACE_REG_RA REG_RA
84 #elif defined(__POWERPC__)
85 #define REPLACE_RA_LINKAGE_AREA
86 #define REPLACE_LEAFMETHODS_RA_REGISTER
87 #define REPLACE_REG_RA REG_ITMP3 /* the execution state has the LR in itmp3 */
91 /*** configuration of native stack slot size **********************************/
93 /* XXX this should be in md-abi.h files, probably */
95 #if defined(HAS_4BYTE_STACKSLOT)
96 #define SIZE_OF_STACKSLOT 4
97 #define STACK_SLOTS_PER_FLOAT 2
98 typedef u4 stackslot_t;
100 #define SIZE_OF_STACKSLOT 8
101 #define STACK_SLOTS_PER_FLOAT 1
102 typedef u8 stackslot_t;
106 /*** debugging ****************************************************************/
108 /*#define REPLACE_VERBOSE*/
111 static void java_value_print(s4 type, replace_val_t value);
112 static void replace_stackframeinfo_println(stackframeinfo *sfi);
115 #if !defined(NDEBUG) && defined(REPLACE_VERBOSE)
116 int replace_verbose = 0;
117 #define DOLOG(code) do{ if (replace_verbose > 1) { code; } } while(0)
118 #define DOLOG_SHORT(code) do{ if (replace_verbose > 0) { code; } } while(0)
121 #define DOLOG_SHORT(code)
125 /*** statistics ***************************************************************/
127 #define REPLACE_STATISTICS
129 #if defined(REPLACE_STATISTICS)
131 static int stat_replacements = 0;
132 static int stat_frames = 0;
133 static int stat_recompile = 0;
134 static int stat_staticpatch = 0;
135 static int stat_unroll_inline = 0;
136 static int stat_unroll_call = 0;
137 static int stat_dist_frames[20] = { 0 };
138 static int stat_dist_locals[20] = { 0 };
139 static int stat_dist_locals_adr[10] = { 0 };
140 static int stat_dist_locals_prim[10] = { 0 };
141 static int stat_dist_locals_ret[10] = { 0 };
142 static int stat_dist_locals_void[10] = { 0 };
143 static int stat_dist_stack[10] = { 0 };
144 static int stat_dist_stack_adr[10] = { 0 };
145 static int stat_dist_stack_prim[10] = { 0 };
146 static int stat_dist_stack_ret[10] = { 0 };
147 static int stat_methods = 0;
148 static int stat_rploints = 0;
149 static int stat_regallocs = 0;
150 static int stat_dist_method_rplpoints[20] = { 0 };
152 #define REPLACE_COUNT(cnt) (cnt)++
153 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
154 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
156 #define REPLACE_COUNT_DIST(array, val) \
158 int limit = (sizeof(array) / sizeof(int)) - 1; \
159 if ((val) < (limit)) (array)[val]++; \
160 else (array)[limit]++; \
163 static void replace_statistics_source_frame(sourceframe_t *frame);
167 #define REPLACE_COUNT(cnt)
168 #define REPLACE_COUNT_IF(cnt, cond)
169 #define REPLACE_COUNT_INC(cnt, inc)
170 #define REPLACE_COUNT_DIST(array, val)
172 #endif /* defined(REPLACE_STATISTICS) */
175 /*** constants used internally ************************************************/
177 #define TOP_IS_NORMAL 0
178 #define TOP_IS_ON_STACK 1
179 #define TOP_IS_IN_ITMP1 2
180 #define TOP_IS_VOID 3
183 /******************************************************************************/
184 /* PART I: Creating / freeing replacement points */
185 /******************************************************************************/
188 /* replace_create_replacement_point ********************************************
190 Create a replacement point.
193 jd...............current jitdata
194 iinfo............inlining info for the current position
195 rp...............pre-allocated (uninitialized) rplpoint
196 type.............RPLPOINT_TYPE constant
197 iptr.............current instruction
198 *pra.............current rplalloc pointer
199 javalocals.......the javalocals at the current point
200 stackvars........the stack variables at the current point
201 stackdepth.......the stack depth at the current point
202 paramcount.......number of parameters at the start of stackvars
205 *rpa.............points to the next free rplalloc
207 *******************************************************************************/
209 static void replace_create_replacement_point(jitdata *jd,
210 insinfo_inline *iinfo,
227 REPLACE_COUNT(stat_rploints);
229 rp->method = (iinfo) ? iinfo->method : jd->m;
230 rp->pc = NULL; /* set by codegen */
231 rp->callsize = 0; /* set by codegen */
235 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
237 /* XXX unify these two fields */
238 rp->parent = (iinfo) ? iinfo->rp : NULL;
240 /* store local allocation info of javalocals */
243 for (i = 0; i < rp->method->maxlocals; ++i) {
244 index = javalocals[i];
249 if (index < UNUSED) {
250 ra->regoff = (UNUSED - index) - 1;
256 ra->flags = v->flags & (INMEMORY);
257 ra->regoff = v->vv.regoff;
264 /* store allocation info of java stack vars */
266 for (i = 0; i < stackdepth; ++i) {
267 v = VAR(stackvars[i]);
268 ra->flags = v->flags & (INMEMORY);
269 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
271 /* XXX how to handle locals on the stack containing returnAddresses? */
272 if (v->type == TYPE_RET) {
273 assert(stackvars[i] >= jd->localcount);
274 ra->regoff = v->vv.retaddr->nr;
277 ra->regoff = v->vv.regoff;
281 /* total number of allocations */
283 rp->regalloccount = ra - rp->regalloc;
289 /* replace_create_inline_start_replacement_point *******************************
291 Create an INLINE_START replacement point.
294 jd...............current jitdata
295 rp...............pre-allocated (uninitialized) rplpoint
296 iptr.............current instruction
297 *pra.............current rplalloc pointer
298 javalocals.......the javalocals at the current point
301 *rpa.............points to the next free rplalloc
304 the insinfo_inline * for the following inlined body
306 *******************************************************************************/
308 static insinfo_inline * replace_create_inline_start_replacement_point(
315 insinfo_inline *calleeinfo;
318 calleeinfo = iptr->sx.s23.s3.inlineinfo;
322 replace_create_replacement_point(jd, calleeinfo->parent, rp,
323 RPLPOINT_TYPE_INLINE, iptr, pra,
325 calleeinfo->stackvars, calleeinfo->stackvarscount,
326 calleeinfo->paramcount);
328 if (calleeinfo->synclocal != UNUSED) {
330 ra->index = RPLALLOC_SYNC;
331 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
332 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
342 /* replace_create_replacement_points *******************************************
344 Create the replacement points for the given code.
347 jd...............current jitdata, must not have any replacement points
350 code->rplpoints.......set to the list of replacement points
351 code->rplpointcount...number of replacement points
352 code->regalloc........list of allocation info
353 code->regalloccount...total length of allocation info list
354 code->globalcount.....number of global allocations at the
355 start of code->regalloc
358 true.............everything ok
359 false............an exception has been thrown
361 *******************************************************************************/
363 #define CLEAR_javalocals(array, method) \
365 for (i=0; i<(method)->maxlocals; ++i) \
366 (array)[i] = UNUSED; \
369 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
371 if ((array) != NULL) \
372 MCOPY((dest), (array), s4, (method)->maxlocals); \
374 CLEAR_javalocals((dest), (method)); \
377 #define COUNT_javalocals(array, method, counter) \
379 for (i=0; i<(method)->maxlocals; ++i) \
380 if ((array)[i] != UNUSED) \
384 bool replace_create_replacement_points(jitdata *jd)
402 insinfo_inline *iinfo;
405 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
409 REPLACE_COUNT(stat_methods);
411 /* get required compiler data */
416 /* assert that we wont overwrite already allocated data */
420 assert(code->rplpoints == NULL);
421 assert(code->rplpointcount == 0);
422 assert(code->regalloc == NULL);
423 assert(code->regalloccount == 0);
424 assert(code->globalcount == 0);
428 /* set codeinfo flags */
430 if (jd->isleafmethod)
431 CODE_SETFLAG_LEAFMETHOD(code);
433 /* in instance methods, we may need a rplpoint at the method entry */
435 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
436 if (!(m->flags & ACC_STATIC)) {
437 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
443 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
445 /* iterate over the basic block list to find replacement points */
450 javalocals = DMNEW(s4, jd->maxlocals);
452 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
456 if (bptr->flags < BBFINISHED)
459 /* get info about this block */
462 iinfo = bptr->inlineinfo;
464 /* initialize javalocals at the start of this block */
466 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
468 /* iterate over the instructions */
471 iend = iptr + bptr->icount;
475 for (; iptr != iend; ++iptr) {
477 case ICMD_INVOKESTATIC:
478 case ICMD_INVOKESPECIAL:
479 case ICMD_INVOKEVIRTUAL:
480 case ICMD_INVOKEINTERFACE:
481 INSTRUCTION_GET_METHODDESC(iptr, md);
483 COUNT_javalocals(javalocals, m, alloccount);
484 alloccount += iptr->s1.argcount;
486 alloccount -= iinfo->throughcount;
494 stack_javalocals_store(iptr, javalocals);
508 case ICMD_INLINE_START:
509 iinfo = iptr->sx.s23.s3.inlineinfo;
512 COUNT_javalocals(javalocals, m, alloccount);
513 alloccount += iinfo->stackvarscount;
514 if (iinfo->synclocal != UNUSED)
518 /* javalocals may be set at next block start, or now */
519 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
522 case ICMD_INLINE_BODY:
523 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
525 jl = iinfo->javalocals_start;
527 /* get the javalocals from the following block start */
529 jl = bptr->next->javalocals;
532 COUNT_javalocals(jl, m, alloccount);
535 case ICMD_INLINE_END:
536 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
537 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
538 iinfo = iptr->sx.s23.s3.inlineinfo;
540 if (iinfo->javalocals_end)
541 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
542 iinfo = iinfo->parent;
546 if (iptr == bptr->iinstr)
548 } /* end instruction loop */
550 /* create replacement points at targets of backward branches */
551 /* We only need the replacement point there, if there is no */
552 /* replacement point inside the block. */
554 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
555 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
556 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
560 if (test > startcount) {
561 /* we don't need an extra rplpoint */
562 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
566 alloccount += bptr->indepth;
567 if (bptr->inlineinfo)
568 alloccount -= bptr->inlineinfo->throughcount;
570 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
574 } /* end basicblock loop */
576 /* if no points were found, there's nothing to do */
581 /* allocate replacement point array and allocation array */
583 rplpoints = MNEW(rplpoint, count);
584 regalloc = MNEW(rplalloc, alloccount);
587 /* initialize replacement point structs */
591 /* XXX try to share code with the counting loop! */
593 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
596 if (bptr->flags < BBFINISHED)
599 /* get info about this block */
602 iinfo = bptr->inlineinfo;
604 /* initialize javalocals at the start of this block */
606 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
608 /* create replacement points at targets of backward branches */
610 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
612 i = (iinfo) ? iinfo->throughcount : 0;
613 replace_create_replacement_point(jd, iinfo, rp++,
614 bptr->type, bptr->iinstr, &ra,
615 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
617 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
618 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
621 /* iterate over the instructions */
624 iend = iptr + bptr->icount;
626 for (; iptr != iend; ++iptr) {
628 case ICMD_INVOKESTATIC:
629 case ICMD_INVOKESPECIAL:
630 case ICMD_INVOKEVIRTUAL:
631 case ICMD_INVOKEINTERFACE:
632 INSTRUCTION_GET_METHODDESC(iptr, md);
634 i = (iinfo) ? iinfo->throughcount : 0;
635 replace_create_replacement_point(jd, iinfo, rp++,
636 RPLPOINT_TYPE_CALL, iptr, &ra,
637 javalocals, iptr->sx.s23.s2.args,
638 iptr->s1.argcount - i,
647 stack_javalocals_store(iptr, javalocals);
655 replace_create_replacement_point(jd, iinfo, rp++,
656 RPLPOINT_TYPE_RETURN, iptr, &ra,
657 NULL, &(iptr->s1.varindex), 1, 0);
661 replace_create_replacement_point(jd, iinfo, rp++,
662 RPLPOINT_TYPE_RETURN, iptr, &ra,
666 case ICMD_INLINE_START:
667 iinfo = replace_create_inline_start_replacement_point(
668 jd, rp++, iptr, &ra, javalocals);
670 /* javalocals may be set at next block start, or now */
671 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
674 case ICMD_INLINE_BODY:
675 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
677 jl = iinfo->javalocals_start;
679 /* get the javalocals from the following block start */
681 jl = bptr->next->javalocals;
683 /* create a non-trappable rplpoint */
684 replace_create_replacement_point(jd, iinfo, rp++,
685 RPLPOINT_TYPE_BODY, iptr, &ra,
687 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
690 case ICMD_INLINE_END:
691 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
692 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
693 iinfo = iptr->sx.s23.s3.inlineinfo;
695 if (iinfo->javalocals_end)
696 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
697 iinfo = iinfo->parent;
700 } /* end instruction loop */
701 } /* end basicblock loop */
703 assert((rp - rplpoints) == count);
704 assert((ra - regalloc) == alloccount);
706 /* store the data in the codeinfo */
708 code->rplpoints = rplpoints;
709 code->rplpointcount = count;
710 code->regalloc = regalloc;
711 code->regalloccount = alloccount;
712 code->globalcount = 0;
713 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
714 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
715 code->memuse = rd->memuse;
716 code->stackframesize = jd->cd->stackframesize;
718 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
719 REPLACE_COUNT_INC(stat_regallocs, alloccount);
721 /* everything alright */
727 /* replace_free_replacement_points *********************************************
729 Free memory used by replacement points.
732 code.............codeinfo whose replacement points should be freed.
734 *******************************************************************************/
736 void replace_free_replacement_points(codeinfo *code)
741 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
744 MFREE(code->regalloc,rplalloc,code->regalloccount);
746 code->rplpoints = NULL;
747 code->rplpointcount = 0;
748 code->regalloc = NULL;
749 code->regalloccount = 0;
750 code->globalcount = 0;
754 /******************************************************************************/
755 /* PART II: Activating / deactivating replacement points */
756 /******************************************************************************/
759 /* replace_activate_replacement_points *****************************************
761 Activate the replacement points of the given compilation unit. When this
762 function returns, the replacement points are "armed", so each thread
763 reaching one of the points will enter the replacement mechanism.
766 code.............codeinfo of which replacement points should be
768 mappable.........if true, only mappable replacement points are
771 *******************************************************************************/
773 void replace_activate_replacement_points(codeinfo *code, bool mappable)
781 assert(code->savedmcode == NULL);
783 /* count trappable replacement points */
787 i = code->rplpointcount;
788 rp = code->rplpoints;
790 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
795 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
801 /* allocate buffer for saved machine code */
803 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
804 code->savedmcode = savedmcode;
805 savedmcode += count * REPLACEMENT_PATCH_SIZE;
807 /* activate trappable replacement points */
808 /* (in reverse order to handle overlapping points within basic blocks) */
810 i = code->rplpointcount;
811 rp = code->rplpoints + i;
813 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
815 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
820 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
823 DOLOG( printf("activate replacement point:\n");
824 replace_replacement_point_println(rp, 1); fflush(stdout); );
826 savedmcode -= REPLACEMENT_PATCH_SIZE;
828 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
829 md_patch_replacement_point(code, index, rp, savedmcode);
831 rp->flags |= RPLPOINT_FLAG_ACTIVE;
834 assert(savedmcode == code->savedmcode);
838 /* replace_deactivate_replacement_points ***************************************
840 Deactivate a replacement points in the given compilation unit.
841 When this function returns, the replacement points will be "un-armed",
842 that is a each thread reaching a point will just continue normally.
845 code.............the compilation unit
847 *******************************************************************************/
849 void replace_deactivate_replacement_points(codeinfo *code)
856 if (code->savedmcode == NULL) {
857 /* disarm countdown points by patching the branches */
859 i = code->rplpointcount;
860 rp = code->rplpoints;
862 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
863 == RPLPOINT_FLAG_COUNTDOWN)
866 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
873 assert(code->savedmcode != NULL);
874 savedmcode = code->savedmcode;
876 /* de-activate each trappable replacement point */
878 i = code->rplpointcount;
879 rp = code->rplpoints;
882 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
887 DOLOG( printf("deactivate replacement point:\n");
888 replace_replacement_point_println(rp, 1); fflush(stdout); );
890 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
891 md_patch_replacement_point(code, -1, rp, savedmcode);
894 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
896 savedmcode += REPLACEMENT_PATCH_SIZE;
899 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
901 /* free saved machine code */
903 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
904 code->savedmcode = NULL;
908 /******************************************************************************/
909 /* PART III: The replacement mechanism */
910 /******************************************************************************/
913 /* replace_read_value **********************************************************
915 Read a value with the given allocation from the execution state.
918 es...............execution state
919 sp...............stack pointer of the execution state (XXX eliminate?)
920 ra...............allocation
921 javaval..........where to put the value
924 *javaval.........the value
926 *******************************************************************************/
928 static void replace_read_value(executionstate_t *es,
931 replace_val_t *javaval)
933 if (ra->flags & INMEMORY) {
934 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
935 #ifdef HAS_4BYTE_STACKSLOT
936 if (IS_2_WORD_TYPE(ra->type)) {
937 javaval->l = *(u8*)(sp + ra->regoff);
941 javaval->p = sp[ra->regoff];
942 #ifdef HAS_4BYTE_STACKSLOT
947 /* allocated register */
948 if (IS_FLT_DBL_TYPE(ra->type)) {
949 javaval->d = es->fltregs[ra->regoff];
951 if (ra->type == TYPE_FLT)
952 javaval->f = javaval->d;
955 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
956 if (ra->type == TYPE_LNG) {
957 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
958 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
961 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
962 javaval->p = es->intregs[ra->regoff];
968 /* replace_write_value *********************************************************
970 Write a value to the given allocation in the execution state.
973 es...............execution state
974 sp...............stack pointer of the execution state (XXX eliminate?)
975 ra...............allocation
976 *javaval.........the value
978 *******************************************************************************/
980 static void replace_write_value(executionstate_t *es,
983 replace_val_t *javaval)
985 if (ra->flags & INMEMORY) {
986 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
987 #ifdef HAS_4BYTE_STACKSLOT
988 if (IS_2_WORD_TYPE(ra->type)) {
989 *(u8*)(sp + ra->regoff) = javaval->l;
993 sp[ra->regoff] = javaval->p;
994 #ifdef HAS_4BYTE_STACKSLOT
999 /* allocated register */
1002 es->fltregs[ra->regoff] = (double) javaval->f;
1005 es->fltregs[ra->regoff] = javaval->d;
1007 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1009 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1010 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1014 es->intregs[ra->regoff] = javaval->p;
1020 /* replace_read_executionstate *************************************************
1022 Read the given executions state and translate it to a source frame.
1025 ss...............the source state
1028 ss->frames.......set to new frame
1031 returns the new frame
1033 *******************************************************************************/
1035 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1037 sourceframe_t *frame;
1039 frame = DNEW(sourceframe_t);
1040 MZERO(frame, sourceframe_t, 1);
1042 frame->down = ss->frames;
1049 /* replace_read_executionstate *************************************************
1051 Read the given executions state and translate it to a source frame.
1054 rp...............replacement point at which `es` was taken
1055 es...............execution state
1056 ss...............where to put the source state
1059 *ss..............the source state derived from the execution state
1061 *******************************************************************************/
1063 static s4 replace_normalize_type_map[] = {
1064 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1065 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1066 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1067 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1068 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1069 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1070 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1074 static void replace_read_executionstate(rplpoint *rp,
1075 executionstate_t *es,
1084 sourceframe_t *frame;
1087 stackslot_t *basesp;
1089 code = code_find_codeinfo_for_pc(rp->pc);
1091 topslot = TOP_IS_NORMAL;
1095 sp = (stackslot_t *) es->sp;
1097 /* in some cases the top stack slot is passed in REG_ITMP1 */
1099 if (rp->type == BBTYPE_EXH) {
1100 topslot = TOP_IS_IN_ITMP1;
1103 /* calculate base stack pointer */
1105 basesp = sp + code_get_stack_frame_size(code);
1107 /* create the source frame */
1109 frame = replace_new_sourceframe(ss);
1110 frame->method = rp->method;
1112 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1113 frame->type = replace_normalize_type_map[rp->type];
1115 frame->fromcode = code;
1117 /* read local variables */
1119 count = m->maxlocals;
1120 frame->javalocalcount = count;
1121 frame->javalocals = DMNEW(replace_val_t, count);
1122 frame->javalocaltype = DMNEW(u1, count);
1124 /* mark values as undefined */
1125 for (i=0; i<count; ++i) {
1126 #if !defined(NDEBUG)
1127 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1129 frame->javalocaltype[i] = TYPE_VOID;
1132 /* some entries in the intregs array are not meaningful */
1133 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1134 #if !defined(NDEBUG)
1135 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1137 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1139 #endif /* !defined(NDEBUG) */
1141 /* read javalocals */
1143 count = rp->regalloccount;
1146 while (count && (i = ra->index) >= 0) {
1147 assert(i < m->maxlocals);
1148 frame->javalocaltype[i] = ra->type;
1149 if (ra->type == TYPE_RET)
1150 frame->javalocals[i].i = ra->regoff;
1152 replace_read_value(es, sp, ra, frame->javalocals + i);
1157 /* read instance, if this is the first rplpoint */
1159 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1160 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1162 /* we are at the start of the method body, so if local 0 is set, */
1163 /* it is the instance. */
1164 if (frame->javalocaltype[0] == TYPE_ADR)
1165 frame->instance = frame->javalocals[0];
1170 md = rp->method->parseddesc;
1172 assert(md->paramcount >= 1);
1173 instra.type = TYPE_ADR;
1174 instra.regoff = md->params[0].regoff;
1175 if (md->params[0].inmemory) {
1176 instra.flags = INMEMORY;
1177 instra.regoff += (1 + code->stackframesize);
1182 replace_read_value(es, sp, &instra, &(frame->instance));
1185 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1187 /* read stack slots */
1189 frame->javastackdepth = count;
1190 frame->javastack = DMNEW(replace_val_t, count);
1191 frame->javastacktype = DMNEW(u1, count);
1193 #if !defined(NDEBUG)
1194 /* mark values as undefined */
1195 for (i=0; i<count; ++i) {
1196 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1197 frame->javastacktype[i] = TYPE_VOID;
1199 #endif /* !defined(NDEBUG) */
1203 /* the first stack slot is special in SBR and EXH blocks */
1205 if (topslot == TOP_IS_ON_STACK) {
1208 assert(ra->index == RPLALLOC_STACK);
1209 assert(ra->type == TYPE_ADR);
1210 frame->javastack[i].p = sp[-1];
1211 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1216 else if (topslot == TOP_IS_IN_ITMP1) {
1219 assert(ra->index == RPLALLOC_STACK);
1220 assert(ra->type == TYPE_ADR);
1221 frame->javastack[i].p = es->intregs[REG_ITMP1];
1222 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1227 else if (topslot == TOP_IS_VOID) {
1230 assert(ra->index == RPLALLOC_STACK);
1231 frame->javastack[i].l = 0;
1232 frame->javastacktype[i] = TYPE_VOID;
1238 /* read remaining stack slots */
1240 for (; count--; ra++) {
1241 if (ra->index == RPLALLOC_SYNC) {
1242 assert(rp->type == RPLPOINT_TYPE_INLINE);
1244 /* only read synchronization slots when traversing an inline point */
1247 sourceframe_t *calleeframe = frame->down;
1248 assert(calleeframe);
1249 assert(calleeframe->syncslotcount == 0);
1250 assert(calleeframe->syncslots == NULL);
1252 calleeframe->syncslotcount = 1;
1253 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1254 replace_read_value(es,sp,ra,calleeframe->syncslots);
1257 frame->javastackdepth--;
1261 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1263 /* do not read parameters of calls down the call chain */
1265 if (!topframe && ra->index == RPLALLOC_PARAM) {
1266 frame->javastackdepth--;
1269 if (ra->type == TYPE_RET)
1270 frame->javastack[i].i = ra->regoff;
1272 replace_read_value(es,sp,ra,frame->javastack + i);
1273 frame->javastacktype[i] = ra->type;
1280 /* replace_write_executionstate ************************************************
1282 Translate the given source state into an execution state.
1285 rp...............replacement point for which execution state should be
1287 es...............where to put the execution state
1288 ss...............the given source state
1291 *es..............the execution state derived from the source state
1293 *******************************************************************************/
1295 static void replace_write_executionstate(rplpoint *rp,
1296 executionstate_t *es,
1305 sourceframe_t *frame;
1308 stackslot_t *basesp;
1310 code = code_find_codeinfo_for_pc(rp->pc);
1312 topslot = TOP_IS_NORMAL;
1314 /* pop a source frame */
1318 ss->frames = frame->down;
1320 /* calculate stack pointer */
1322 sp = (stackslot_t *) es->sp;
1324 basesp = sp + code_get_stack_frame_size(code);
1326 /* in some cases the top stack slot is passed in REG_ITMP1 */
1328 if (rp->type == BBTYPE_EXH) {
1329 topslot = TOP_IS_IN_ITMP1;
1332 /* write javalocals */
1335 count = rp->regalloccount;
1337 while (count && (i = ra->index) >= 0) {
1338 assert(i < m->maxlocals);
1339 assert(i < frame->javalocalcount);
1340 assert(ra->type == frame->javalocaltype[i]);
1341 if (ra->type == TYPE_RET) {
1342 /* XXX assert that it matches this rplpoint */
1345 replace_write_value(es, sp, ra, frame->javalocals + i);
1350 /* write stack slots */
1354 /* the first stack slot is special in SBR and EXH blocks */
1356 if (topslot == TOP_IS_ON_STACK) {
1359 assert(ra->index == RPLALLOC_STACK);
1360 assert(i < frame->javastackdepth);
1361 assert(frame->javastacktype[i] == TYPE_ADR);
1362 sp[-1] = frame->javastack[i].p;
1367 else if (topslot == TOP_IS_IN_ITMP1) {
1370 assert(ra->index == RPLALLOC_STACK);
1371 assert(i < frame->javastackdepth);
1372 assert(frame->javastacktype[i] == TYPE_ADR);
1373 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1378 else if (topslot == TOP_IS_VOID) {
1381 assert(ra->index == RPLALLOC_STACK);
1382 assert(i < frame->javastackdepth);
1383 assert(frame->javastacktype[i] == TYPE_VOID);
1389 /* write remaining stack slots */
1391 for (; count--; ra++) {
1392 if (ra->index == RPLALLOC_SYNC) {
1393 assert(rp->type == RPLPOINT_TYPE_INLINE);
1395 /* only write synchronization slots when traversing an inline point */
1398 assert(frame->down);
1399 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1400 assert(frame->down->syncslots != NULL);
1402 replace_write_value(es,sp,ra,frame->down->syncslots);
1407 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1409 /* do not write parameters of calls down the call chain */
1411 if (!topframe && ra->index == RPLALLOC_PARAM) {
1415 assert(i < frame->javastackdepth);
1416 assert(ra->type == frame->javastacktype[i]);
1417 if (ra->type == TYPE_RET) {
1418 /* XXX assert that it matches this rplpoint */
1421 replace_write_value(es,sp,ra,frame->javastack + i);
1433 /* replace_pop_activation_record ***********************************************
1435 Peel a stack frame from the execution state.
1437 *** This function imitates the effects of the method epilog ***
1438 *** and returning from the method call. ***
1441 es...............execution state
1442 frame............source frame, receives synchronization slots
1445 *es..............the execution state after popping the stack frame
1447 *******************************************************************************/
1449 u1* replace_pop_activation_record(executionstate_t *es,
1450 sourceframe_t *frame)
1458 stackslot_t *basesp;
1464 /* read the return address */
1466 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1467 if (CODE_IS_LEAFMETHOD(es->code))
1468 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1471 ra = md_stacktrace_get_returnaddress(es->sp,
1472 SIZE_OF_STACKSLOT * es->code->stackframesize);
1474 DOLOG( printf("return address: %p\n", (void*)ra); );
1478 /* calculate the base of the stack frame */
1480 sp = (stackslot_t *) es->sp;
1481 basesp = sp + es->code->stackframesize;
1483 /* read slots used for synchronization */
1485 assert(frame->syncslotcount == 0);
1486 assert(frame->syncslots == NULL);
1487 count = code_get_sync_slot_count(es->code);
1488 frame->syncslotcount = count;
1489 frame->syncslots = DMNEW(replace_val_t, count);
1490 for (i=0; i<count; ++i) {
1491 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1494 /* restore return address, if part of frame */
1496 #if defined(REPLACE_RA_TOP_OF_FRAME)
1497 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1498 if (!CODE_IS_LEAFMETHOD(es->code))
1500 es->intregs[REPLACE_REG_RA] = *--basesp;
1501 #endif /* REPLACE_RA_TOP_OF_FRAME */
1503 #if defined(REPLACE_RA_LINKAGE_AREA)
1504 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1505 if (!CODE_IS_LEAFMETHOD(es->code))
1507 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1508 #endif /* REPLACE_RA_LINKAGE_AREA */
1510 /* restore saved int registers */
1513 for (i=0; i<es->code->savedintcount; ++i) {
1514 while (nregdescint[--reg] != REG_SAV)
1516 es->intregs[reg] = *--basesp;
1519 /* restore saved flt registers */
1523 for (i=0; i<es->code->savedfltcount; ++i) {
1524 while (nregdescfloat[--reg] != REG_SAV)
1526 basesp -= STACK_SLOTS_PER_FLOAT;
1527 es->fltregs[reg] = *(double*)basesp;
1530 /* adjust the stackpointer */
1532 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1534 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1535 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1538 /* Set the new pc. Subtract one so we do not hit the replacement point */
1539 /* of the instruction following the call, if there is one. */
1543 /* find the new codeinfo */
1545 pv = md_codegen_get_pv_from_pc(ra);
1547 DOLOG( printf("PV = %p\n", (void*) pv); );
1549 if (pv == NULL) /* XXX can this really happen? */
1552 code = *(codeinfo **)(pv + CodeinfoPointer);
1554 DOLOG( printf("CODE = %p\n", (void*) code); );
1556 /* return NULL if we reached native code */
1561 /* in debugging mode clobber non-saved registers */
1563 #if !defined(NDEBUG)
1565 for (i=0; i<INT_REG_CNT; ++i)
1566 if ((nregdescint[i] != REG_SAV)
1568 && (i != REPLACE_REG_RA)
1571 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1572 for (i=0; i<FLT_REG_CNT; ++i)
1573 if (nregdescfloat[i] != REG_SAV)
1574 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1575 #endif /* !defined(NDEBUG) */
1577 return (code) ? ra : NULL;
1581 /* replace_patch_method_pointer ************************************************
1583 Patch a method pointer (may be in code, data segment, vftbl, or interface
1587 mpp..............address of the method pointer to patch
1588 entrypoint.......the new entrypoint of the method
1589 kind.............kind of call to patch, used only for debugging
1591 *******************************************************************************/
1593 static void replace_patch_method_pointer(methodptr *mpp,
1594 methodptr entrypoint,
1597 #if !defined(NDEBUG)
1602 DOLOG( printf("patch method pointer from: %p to %p\n",
1603 (void*) *mpp, (void*)entrypoint); );
1605 #if !defined(NDEBUG)
1606 oldcode = *(codeinfo **)((u1*)(*mpp) + CodeinfoPointer);
1607 newcode = *(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer);
1609 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1610 method_println(oldcode->m);
1611 printf("\t with %p ", (void*) newcode);
1612 method_println(newcode->m); );
1614 assert(oldcode->m == newcode->m);
1617 /* write the new entrypoint */
1619 *mpp = (methodptr) entrypoint;
1623 /* replace_patch_class *********************************************************
1625 Patch a method in the given class.
1628 vftbl............vftbl of the class
1629 m................the method to patch
1630 oldentrypoint....the old entrypoint to replace
1631 entrypoint.......the new entrypoint
1633 *******************************************************************************/
1635 void replace_patch_class(vftbl_t *vftbl,
1644 /* patch the vftbl of the class */
1646 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1650 /* patch the interface tables */
1652 assert(oldentrypoint);
1654 for (i=0; i < vftbl->interfacetablelength; ++i) {
1655 mpp = vftbl->interfacetable[-i];
1656 mppend = mpp + vftbl->interfacevftbllength[i];
1657 for (; mpp != mppend; ++mpp)
1658 if (*mpp == oldentrypoint) {
1659 replace_patch_method_pointer(mpp, entrypoint, "interface");
1665 /* replace_patch_class_hierarchy ***********************************************
1667 Patch a method in all loaded classes.
1670 m................the method to patch
1671 oldentrypoint....the old entrypoint to replace
1672 entrypoint.......the new entrypoint
1674 *******************************************************************************/
1676 struct replace_patch_data_t {
1682 #define CODEINFO_OF_CODE(entrypoint) \
1683 (*(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer))
1685 #define METHOD_OF_CODE(entrypoint) \
1686 (CODEINFO_OF_CODE(entrypoint)->m)
1688 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1690 vftbl_t *vftbl = c->vftbl;
1693 && vftbl->vftbllength > pd->m->vftblindex
1694 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1695 && METHOD_OF_CODE(vftbl->table[pd->m->vftblindex]) == pd->m)
1697 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1701 void replace_patch_class_hierarchy(methodinfo *m,
1705 struct replace_patch_data_t pd;
1708 pd.oldentrypoint = oldentrypoint;
1709 pd.entrypoint = entrypoint;
1711 DOLOG_SHORT( printf("patching class hierarchy: ");
1712 method_println(m); );
1714 classcache_foreach_loaded_class(
1715 (classcache_foreach_functionptr_t) &replace_patch_callback,
1720 /* replace_patch_future_calls **************************************************
1722 Analyse a call site and depending on the kind of call patch the call, the
1723 virtual function table, or the interface table.
1726 ra...............return address pointing after the call site
1727 callerframe......source frame of the caller
1728 calleeframe......source frame of the callee, must have been mapped
1730 *******************************************************************************/
1732 void replace_patch_future_calls(u1 *ra,
1733 sourceframe_t *callerframe,
1734 sourceframe_t *calleeframe)
1737 methodptr entrypoint;
1738 methodptr oldentrypoint;
1741 codeinfo *calleecode;
1742 methodinfo *calleem;
1743 java_objectheader *obj;
1747 assert(callerframe->down == calleeframe);
1749 /* get the new codeinfo and the method that shall be entered */
1751 calleecode = calleeframe->tocode;
1754 calleem = calleeframe->method;
1755 assert(calleem == calleecode->m);
1757 entrypoint = (methodptr) calleecode->entrypoint;
1759 /* check if we are at an method entry rplpoint at the innermost frame */
1761 atentry = (calleeframe->down == NULL)
1762 && !(calleem->flags & ACC_STATIC)
1763 && (calleeframe->fromrp->id == 0); /* XXX */
1765 /* get the position to patch, in case it was a statically bound call */
1767 sfi.pv = callerframe->fromcode->entrypoint;
1768 patchpos = md_get_method_patch_address(ra, &sfi, NULL);
1770 if (patchpos == NULL) {
1771 /* the call was dispatched dynamically */
1773 /* we can only patch such calls if we are at the entry point */
1778 assert((calleem->flags & ACC_STATIC) == 0);
1780 oldentrypoint = calleeframe->fromcode->entrypoint;
1782 /* we need to know the instance */
1784 if (!calleeframe->instance.a) {
1785 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1786 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1792 obj = calleeframe->instance.a;
1795 assert(vftbl->class->vftbl == vftbl);
1797 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1799 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1802 /* the call was statically bound */
1804 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1809 /* replace_push_activation_record **********************************************
1811 Push a stack frame onto the execution state.
1813 *** This function imitates the effects of a call and the ***
1814 *** method prolog of the callee. ***
1817 es...............execution state
1818 rpcall...........the replacement point at the call site
1819 callerframe......source frame of the caller, or NULL for creating the
1821 calleeframe......source frame of the callee, must have been mapped
1824 *es..............the execution state after pushing the stack frame
1826 *******************************************************************************/
1828 void replace_push_activation_record(executionstate_t *es,
1830 sourceframe_t *callerframe,
1831 sourceframe_t *calleeframe)
1836 stackslot_t *basesp;
1839 codeinfo *calleecode;
1842 assert(!rpcall || callerframe);
1843 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1844 assert(!rpcall || rpcall == callerframe->torp);
1845 assert(calleeframe);
1846 assert(!callerframe || calleeframe == callerframe->down);
1848 /* the compilation unit we are entering */
1850 calleecode = calleeframe->tocode;
1853 /* calculate the return address */
1856 ra = rpcall->pc + rpcall->callsize;
1858 ra = es->pc + 1 /* XXX this is ugly */;
1860 /* write the return address */
1862 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1863 es->sp -= SIZE_OF_STACKSLOT;
1865 *((stackslot_t *)es->sp) = (stackslot_t) ra;
1866 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1868 #if defined(REPLACE_REG_RA)
1869 es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1872 /* we move into a new code unit */
1874 es->code = calleecode;
1876 /* set the new pc XXX not needed? */
1878 es->pc = calleecode->entrypoint;
1880 /* build the stackframe */
1882 DOLOG( printf("building stackframe of %d words at %p\n",
1883 calleecode->stackframesize, (void*)es->sp); );
1885 sp = (stackslot_t *) es->sp;
1888 sp -= calleecode->stackframesize;
1891 /* in debug mode, invalidate stack frame first */
1893 /* XXX may not invalidate linkage area used by native code! */
1894 #if !defined(NDEBUG) && 0
1895 for (i=0; i<(basesp - sp); ++i) {
1896 sp[i] = 0xdeaddeadU;
1900 /* save the return address register */
1902 #if defined(REPLACE_RA_TOP_OF_FRAME)
1903 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1904 if (!CODE_IS_LEAFMETHOD(calleecode))
1906 *--basesp = (ptrint) ra;
1907 #endif /* REPLACE_RA_TOP_OF_FRAME */
1909 #if defined(REPLACE_RA_LINKAGE_AREA)
1910 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1911 if (!CODE_IS_LEAFMETHOD(calleecode))
1913 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1914 #endif /* REPLACE_RA_LINKAGE_AREA */
1916 /* save int registers */
1919 for (i=0; i<calleecode->savedintcount; ++i) {
1920 while (nregdescint[--reg] != REG_SAV)
1922 *--basesp = es->intregs[reg];
1924 /* XXX may not clobber saved regs used by native code! */
1925 #if !defined(NDEBUG) && 0
1926 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1930 /* save flt registers */
1934 for (i=0; i<calleecode->savedfltcount; ++i) {
1935 while (nregdescfloat[--reg] != REG_SAV)
1937 basesp -= STACK_SLOTS_PER_FLOAT;
1938 *(double*)basesp = es->fltregs[reg];
1940 /* XXX may not clobber saved regs used by native code! */
1941 #if !defined(NDEBUG) && 0
1942 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1946 /* write slots used for synchronization */
1948 count = code_get_sync_slot_count(calleecode);
1949 assert(count == calleeframe->syncslotcount);
1950 for (i=0; i<count; ++i) {
1951 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
1956 es->pv = calleecode->entrypoint;
1958 /* redirect future invocations */
1960 if (callerframe && rpcall) {
1961 #if defined(REPLACE_PATCH_ALL)
1962 if (rpcall->type == callerframe->fromrp->type)
1964 if (rpcall == callerframe->fromrp)
1966 replace_patch_future_calls(ra, callerframe, calleeframe);
1971 /* replace_find_replacement_point **********************************************
1973 Find the replacement point in the given code corresponding to the
1974 position given in the source frame.
1977 code.............the codeinfo in which to search the rplpoint
1978 frame............the source frame defining the position to look for
1979 parent...........parent replacement point to match
1982 the replacement point
1984 *******************************************************************************/
1986 rplpoint * replace_find_replacement_point(codeinfo *code,
1987 sourceframe_t *frame,
2000 DOLOG( printf("searching replacement point for:\n");
2001 replace_source_frame_println(frame); );
2005 DOLOG( printf("code = %p\n", (void*)code); );
2007 rp = code->rplpoints;
2008 i = code->rplpointcount;
2010 if (rp->id == frame->id && rp->method == frame->method
2011 && rp->parent == parent
2012 && replace_normalize_type_map[rp->type] == frame->type)
2014 /* check if returnAddresses match */
2015 /* XXX optimize: only do this if JSRs in method */
2016 DOLOG( printf("checking match for:");
2017 replace_replacement_point_println(rp, 1); fflush(stdout); );
2020 for (j = rp->regalloccount; j--; ++ra) {
2021 if (ra->type == TYPE_RET) {
2022 if (ra->index == RPLALLOC_STACK) {
2023 assert(stacki < frame->javastackdepth);
2024 if (frame->javastack[stacki].i != ra->regoff)
2029 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2030 if (frame->javalocals[ra->index].i != ra->regoff)
2043 #if !defined(NDEBUG)
2044 printf("candidate replacement points were:\n");
2045 rp = code->rplpoints;
2046 i = code->rplpointcount;
2048 replace_replacement_point_println(rp, 1);
2052 vm_abort("no matching replacement point found");
2053 return NULL; /* NOT REACHED */
2057 /* replace_find_replacement_point_for_pc ***************************************
2059 Find the nearest replacement point at or before the given PC.
2062 code.............compilation unit the PC is in
2063 pc...............the machine code PC
2066 the replacement point found, or
2067 NULL if no replacement point was found
2069 *******************************************************************************/
2071 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2077 DOLOG( printf("searching for rp in %p ", (void*)code);
2078 method_println(code->m); );
2082 rp = code->rplpoints;
2083 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2084 DOLOG( replace_replacement_point_println(rp, 2); );
2093 /* replace_pop_native_frame ****************************************************
2095 Unroll a native frame in the execution state and create a source frame
2099 es...............current execution state
2100 ss...............the current source state
2101 sfi..............stackframeinfo for the native frame
2104 es...............execution state after unrolling the native frame
2105 ss...............gets the added native source frame
2107 *******************************************************************************/
2109 static void replace_pop_native_frame(executionstate_t *es,
2111 stackframeinfo *sfi)
2113 sourceframe_t *frame;
2119 frame = replace_new_sourceframe(ss);
2123 /* remember pc and size of native frame */
2125 frame->nativepc = es->pc;
2126 frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2127 assert(frame->nativeframesize >= 0);
2129 /* remember values of saved registers */
2132 for (i=0; i<INT_REG_CNT; ++i) {
2133 if (nregdescint[i] == REG_SAV)
2134 frame->nativesavint[j++] = es->intregs[i];
2138 for (i=0; i<FLT_REG_CNT; ++i) {
2139 if (nregdescfloat[i] == REG_SAV)
2140 frame->nativesavflt[j++] = es->fltregs[i];
2143 /* restore saved registers */
2145 #if defined(ENABLE_GC_CACAO)
2147 for (i=0; i<INT_REG_CNT; ++i) {
2148 if (nregdescint[i] == REG_SAV)
2149 es->intregs[i] = sfi->intregs[j++];
2152 /* XXX we don't have them, yet, in the sfi, so clear them */
2154 for (i=0; i<INT_REG_CNT; ++i) {
2155 if (nregdescint[i] == REG_SAV)
2160 /* XXX we don't have float registers in the sfi, so clear them */
2162 for (i=0; i<FLT_REG_CNT; ++i) {
2163 if (nregdescfloat[i] == REG_SAV)
2164 es->fltregs[i] = 0.0;
2167 /* restore pv, pc, and sp */
2169 if (sfi->pv == NULL) {
2170 /* frame of a native function call */
2171 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2176 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2179 /* find the new codeinfo */
2181 DOLOG( printf("PV = %p\n", (void*) es->pv); );
2183 assert(es->pv != NULL);
2185 code = *(codeinfo **)(es->pv + CodeinfoPointer);
2187 DOLOG( printf("CODE = %p\n", (void*) code); );
2193 /* replace_push_native_frame ***************************************************
2195 Rebuild a native frame onto the execution state and remove its source frame.
2197 Note: The native frame is "rebuild" by setting fields like PC and stack
2198 pointer in the execution state accordingly. Values in the
2199 stackframeinfo may be modified, but the actual stack frame of the
2200 native code is not touched.
2203 es...............current execution state
2204 ss...............the current source state
2207 es...............execution state after re-rolling the native frame
2208 ss...............the native source frame is removed
2210 *******************************************************************************/
2212 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2214 sourceframe_t *frame;
2220 DOLOG( printf("pushing native frame\n"); );
2222 /* remove the frame from the source state */
2226 assert(REPLACE_IS_NATIVE_FRAME(frame));
2228 ss->frames = frame->down;
2230 /* assert that the native frame has not moved */
2232 assert(es->sp == frame->sfi->sp);
2234 /* update saved registers in the stackframeinfo */
2236 #if defined(ENABLE_GC_CACAO)
2238 for (i=0; i<INT_REG_CNT; ++i) {
2239 if (nregdescint[i] == REG_SAV)
2240 frame->sfi->intregs[j++] = es->intregs[i];
2243 /* XXX leave float registers untouched here */
2246 /* restore saved registers */
2249 for (i=0; i<INT_REG_CNT; ++i) {
2250 if (nregdescint[i] == REG_SAV)
2251 es->intregs[i] = frame->nativesavint[j++];
2255 for (i=0; i<FLT_REG_CNT; ++i) {
2256 if (nregdescfloat[i] == REG_SAV)
2257 es->fltregs[i] = frame->nativesavflt[j++];
2260 /* skip the native frame on the machine stack */
2262 es->sp -= frame->nativeframesize;
2264 /* set the pc the next frame must return to */
2266 es->pc = frame->nativepc;
2270 /* replace_recover_source_state ************************************************
2272 Recover the source state from the given replacement point and execution
2276 rp...............replacement point that has been reached, if any
2277 sfi..............stackframeinfo, if called from native code
2278 es...............execution state at the replacement point rp
2283 *******************************************************************************/
2285 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2286 stackframeinfo *sfi,
2287 executionstate_t *es)
2292 #if defined(REPLACE_STATISTICS)
2296 /* create the source frame structure in dump memory */
2298 ss = DNEW(sourcestate_t);
2301 /* each iteration of the loop recovers one source frame */
2308 DOLOG( replace_executionstate_println(es); );
2310 /* if we are not at a replacement point, it is a native frame */
2313 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2316 replace_pop_native_frame(es, ss, sfi);
2319 if (es->code == NULL)
2322 goto after_machine_frame;
2325 /* read the values for this source frame from the execution state */
2327 DOLOG( printf("recovering source state for%s:\n",
2328 (ss->frames == NULL) ? " TOPFRAME" : "");
2329 replace_replacement_point_println(rp, 1); );
2331 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2333 #if defined(REPLACE_STATISTICS)
2334 REPLACE_COUNT(stat_frames);
2336 replace_statistics_source_frame(ss->frames);
2339 /* in locked areas (below native frames), identity map the frame */
2342 ss->frames->torp = ss->frames->fromrp;
2343 ss->frames->tocode = ss->frames->fromcode;
2346 /* unroll to the next (outer) frame */
2349 /* this frame is in inlined code */
2351 DOLOG( printf("INLINED!\n"); );
2355 assert(rp->type == RPLPOINT_TYPE_INLINE);
2356 REPLACE_COUNT(stat_unroll_inline);
2359 /* this frame had been called at machine-level. pop it. */
2361 DOLOG( printf("UNWIND\n"); );
2363 ra = replace_pop_activation_record(es, ss->frames);
2365 DOLOG( printf("REACHED NATIVE CODE\n"); );
2369 break; /* XXX remove to activate native frames */
2373 /* find the replacement point at the call site */
2375 after_machine_frame:
2376 rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2379 vm_abort("could not find replacement point while unrolling call");
2381 DOLOG( printf("found replacement point.\n");
2382 replace_replacement_point_println(rp, 1); );
2384 assert(rp->type == RPLPOINT_TYPE_CALL);
2385 REPLACE_COUNT(stat_unroll_call);
2387 } /* end loop over source frames */
2389 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2395 /* replace_map_source_state ****************************************************
2397 Map each source frame in the given source state to a target replacement
2398 point and compilation unit. If no valid code is available for a source
2399 frame, it is (re)compiled.
2402 ss...............the source state
2405 ss...............the source state, modified: The `torp` and `tocode`
2406 fields of each source frame are set.
2409 true.............everything went ok
2410 false............an exception has been thrown
2412 *******************************************************************************/
2414 static bool replace_map_source_state(sourcestate_t *ss)
2416 sourceframe_t *frame;
2419 rplpoint *parent; /* parent of inlined rplpoint */
2420 #if defined(REPLACE_STATISTICS)
2427 /* iterate over the source frames from outermost to innermost */
2429 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2431 /* XXX skip native frames */
2433 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2438 /* map frames which are not already mapped */
2440 if (frame->tocode) {
2441 code = frame->tocode;
2446 assert(frame->torp == NULL);
2448 if (parent == NULL) {
2449 /* find code for this frame */
2451 #if defined(REPLACE_STATISTICS)
2452 oldcode = frame->method->code;
2454 /* request optimization of hot methods and their callers */
2456 if (frame->method->hitcountdown < 0
2457 || (frame->down && frame->down->method->hitcountdown < 0))
2458 jit_request_optimization(frame->method);
2460 code = jit_get_current_code(frame->method);
2463 return false; /* exception */
2465 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2470 /* map this frame */
2472 rp = replace_find_replacement_point(code, frame, parent);
2474 frame->tocode = code;
2478 if (rp->type == RPLPOINT_TYPE_CALL) {
2491 /* replace_map_source_state_identity *******************************************
2493 Map each source frame in the given source state to the same replacement
2494 point and compilation unit it was derived from. This is mainly used for
2498 ss...............the source state
2501 ss...............the source state, modified: The `torp` and `tocode`
2502 fields of each source frame are set.
2504 *******************************************************************************/
2506 #if defined(ENABLE_GC_CACAO)
2507 static void replace_map_source_state_identity(sourcestate_t *ss)
2509 sourceframe_t *frame;
2511 /* iterate over the source frames from outermost to innermost */
2513 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2515 /* skip native frames */
2517 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2521 /* map frames using the identity mapping */
2523 if (frame->tocode) {
2524 assert(frame->tocode == frame->fromcode);
2525 assert(frame->torp == frame->fromrp);
2527 assert(frame->tocode == NULL);
2528 assert(frame->torp == NULL);
2529 frame->tocode = frame->fromcode;
2530 frame->torp = frame->fromrp;
2537 /* replace_build_execution_state_intern ****************************************
2539 Build an execution state for the given (mapped) source state.
2541 !!! CAUTION: This function rewrites the machine stack !!!
2543 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2546 ss...............the source state. Must have been mapped by
2547 replace_map_source_state before.
2548 es...............the base execution state on which to build
2551 *es..............the new execution state
2553 *******************************************************************************/
2555 void replace_build_execution_state_intern(sourcestate_t *ss,
2556 executionstate_t *es)
2559 sourceframe_t *prevframe;
2566 while (ss->frames) {
2568 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2569 prevframe = ss->frames;
2570 replace_push_native_frame(es, ss);
2576 if (parent == NULL) {
2577 /* create a machine-level stack frame */
2579 DOLOG( printf("pushing activation record for:\n");
2580 if (rp) replace_replacement_point_println(rp, 1);
2581 else printf("\tfirst frame\n"); );
2583 replace_push_activation_record(es, rp, prevframe, ss->frames);
2585 DOLOG( replace_executionstate_println(es); );
2588 rp = ss->frames->torp;
2591 DOLOG( printf("creating execution state for%s:\n",
2592 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2593 replace_replacement_point_println(ss->frames->fromrp, 1);
2594 replace_replacement_point_println(rp, 1); );
2596 es->code = ss->frames->tocode;
2597 prevframe = ss->frames;
2598 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2600 DOLOG( replace_executionstate_println(es); );
2602 if (rp->type == RPLPOINT_TYPE_CALL) {
2613 /* replace_build_execution_state ***********************************************
2615 This function contains the final phase of replacement. It builds the new
2616 execution state, releases dump memory, and returns to the calling
2617 assembler function which finishes replacement.
2619 NOTE: This function is called from asm_replacement_in, with the stack
2620 pointer at the start of the safe stack area.
2622 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2624 CAUTION: This function and its children must not use a lot of stack!
2625 There are only REPLACE_SAFESTACK_SIZE bytes of C stack
2629 st...............the safestack contained the necessary data
2631 *******************************************************************************/
2633 void replace_build_execution_state(replace_safestack_t *st)
2635 replace_build_execution_state_intern(st->ss, &(st->es));
2637 DOLOG( replace_executionstate_println(&(st->es)); );
2639 /* release dump area */
2641 dump_release(st->dumpsize);
2643 /* new code is entered after returning */
2645 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2649 /* replace_alloc_safestack *****************************************************
2651 Allocate a safe stack area to use during the final phase of replacement.
2652 The returned area is not initialized. This must be done by the caller.
2655 a newly allocated replace_safestack_t *
2657 *******************************************************************************/
2659 static replace_safestack_t *replace_alloc_safestack()
2662 replace_safestack_t *st;
2664 mem = MNEW(u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2666 st = (replace_safestack_t *) ((ptrint)(mem + REPLACE_STACK_ALIGNMENT - 1)
2667 & ~(REPLACE_STACK_ALIGNMENT - 1));
2669 #if !defined(NDEBUG)
2670 memset(st, 0xa5, sizeof(replace_safestack_t));
2679 /* replace_free_safestack ******************************************************
2681 Free the given safestack structure, making a copy of the contained
2682 execution state before freeing it.
2684 NOTE: This function is called from asm_replacement_in.
2687 st...............the safestack to free
2688 tmpes............where to copy the execution state to
2691 *tmpes...........receives a copy of st->es
2693 *******************************************************************************/
2695 void replace_free_safestack(replace_safestack_t *st, executionstate_t *tmpes)
2699 /* copy the executionstate_t to the temporary location */
2703 /* get the memory address to free */
2707 /* destroy memory (in debug mode) */
2709 #if !defined(NDEBUG)
2710 memset(st, 0xa5, sizeof(replace_safestack_t));
2713 /* free the safe stack struct */
2715 MFREE(mem, u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2719 /* replace_me ******************************************************************
2721 This function is called by asm_replacement_out when a thread reaches
2722 a replacement point. `replace_me` must map the execution state to the
2723 target replacement point and let execution continue there.
2725 This function never returns!
2728 rp...............replacement point that has been reached
2729 es...............execution state read by asm_replacement_out
2731 *******************************************************************************/
2733 void replace_me(rplpoint *rp, executionstate_t *es)
2735 stackframeinfo *sfi;
2737 sourceframe_t *frame;
2740 replace_safestack_t *safestack;
2741 #if defined(ENABLE_GC_CACAO)
2742 threadobject *thread;
2746 es->code = code_find_codeinfo_for_pc(rp->pc);
2748 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2749 stat_replacements, (void*)THREADOBJECT,
2751 method_println(es->code->m); );
2753 DOLOG( replace_replacement_point_println(rp, 1);
2754 replace_executionstate_println(es); );
2756 REPLACE_COUNT(stat_replacements);
2758 /* mark start of dump memory area */
2760 dumpsize = dump_size();
2762 /* get the stackframeinfo for the current thread */
2764 sfi = *(STACKFRAMEINFO);
2766 /* recover source state */
2768 ss = replace_recover_source_state(rp, sfi, es);
2770 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2771 /* if there is a collection pending, we assume the replacement point should
2772 suspend this thread */
2776 thread = THREADOBJECT;
2778 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2780 /* map the sourcestate using the identity mapping */
2781 replace_map_source_state_identity(ss);
2783 /* since we enter the same method again, we turn off rps now */
2784 /* XXX michi: can we really do this? what if the rp was active before
2785 we activated it for the gc? */
2788 frame = frame->down;
2789 replace_deactivate_replacement_points(frame->tocode);
2791 /* remember executionstate and sourcestate for this thread */
2792 GC_EXECUTIONSTATE = es;
2793 GC_SOURCESTATE = ss;
2795 /* really suspend this thread now (PC = 0) */
2796 threads_suspend_ack(NULL, NULL);
2798 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2801 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2803 /* map the source state */
2805 if (!replace_map_source_state(ss))
2806 vm_abort("exception during method replacement");
2808 DOLOG( replace_sourcestate_println(ss); );
2810 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2812 /* avoid infinite loops by self-replacement */
2816 frame = frame->down;
2818 if (frame->torp == origrp) {
2820 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2822 replace_deactivate_replacement_points(frame->tocode);
2825 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2829 /* write execution state of new code */
2831 DOLOG( replace_executionstate_println(es); );
2833 /* allocate a safe stack area and copy all needed data there */
2835 safestack = replace_alloc_safestack();
2837 safestack->es = *es;
2839 safestack->dumpsize = dumpsize;
2841 /* call the assembler code for the last phase of replacement */
2843 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
2844 asm_replacement_in(&(safestack->es), safestack);
2847 abort(); /* NOT REACHED */
2851 /******************************************************************************/
2852 /* NOTE: Stuff specific to the exact GC is below. */
2853 /******************************************************************************/
2855 #if defined(ENABLE_GC_CACAO)
2856 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
2858 stackframeinfo *sfi;
2859 executionstate_t *es;
2862 /* get the stackframeinfo of this thread */
2863 assert(thread == THREADOBJECT);
2864 sfi = *( STACKFRAMEINFO );
2866 /* create the execution state */
2867 es = DNEW(executionstate_t);
2870 es->pv = 0; /* since we are in a native, PV is invalid! */
2871 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
2873 /* we assume we are in a native (no replacement point)! */
2874 ss = replace_recover_source_state(NULL, sfi, es);
2876 /* map the sourcestate using the identity mapping */
2877 replace_map_source_state_identity(ss);
2879 /* remember executionstate and sourcestate for this thread */
2880 GC_EXECUTIONSTATE = es;
2881 GC_SOURCESTATE = ss;
2886 /******************************************************************************/
2887 /* NOTE: No important code below. */
2888 /******************************************************************************/
2891 /* statistics *****************************************************************/
2893 #if defined(REPLACE_STATISTICS)
2894 static void print_freq(FILE *file,int *array,int limit)
2899 for (i=0; i<limit; ++i)
2901 sum += array[limit];
2902 for (i=0; i<limit; ++i) {
2904 fprintf(file," %3d: %8d (cum %3d%%)\n",
2905 i, array[i], (sum) ? ((100*cum)/sum) : 0);
2907 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
2909 #endif /* defined(REPLACE_STATISTICS) */
2912 #if defined(REPLACE_STATISTICS)
2914 #define REPLACE_PRINT_DIST(name, array) \
2915 printf(" " name " distribution:\n"); \
2916 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
2918 void replace_print_statistics(void)
2920 printf("replacement statistics:\n");
2921 printf(" # of replacements: %d\n", stat_replacements);
2922 printf(" # of frames: %d\n", stat_frames);
2923 printf(" # of recompilations: %d\n", stat_recompile);
2924 printf(" patched static calls:%d\n", stat_staticpatch);
2925 printf(" unrolled inlines: %d\n", stat_unroll_inline);
2926 printf(" unrolled calls: %d\n", stat_unroll_call);
2927 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
2928 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
2929 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
2930 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
2931 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
2932 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
2933 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
2934 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
2935 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
2936 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
2938 printf(" # of methods: %d\n", stat_methods);
2939 printf(" # of replacement points: %d\n", stat_rploints);
2940 printf(" # of regallocs: %d\n", stat_regallocs);
2941 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
2942 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
2943 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
2947 #endif /* defined(REPLACE_STATISTICS) */
2950 #if defined(REPLACE_STATISTICS)
2951 static void replace_statistics_source_frame(sourceframe_t *frame)
2960 for (i=0; i<frame->javalocalcount; ++i) {
2961 switch (frame->javalocaltype[i]) {
2962 case TYPE_ADR: adr++; break;
2963 case TYPE_RET: ret++; break;
2964 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
2965 case TYPE_VOID: vd++; break;
2970 REPLACE_COUNT_DIST(stat_dist_locals, n);
2971 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
2972 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
2973 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
2974 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
2975 adr = ret = prim = n = 0;
2976 for (i=0; i<frame->javastackdepth; ++i) {
2977 switch (frame->javastacktype[i]) {
2978 case TYPE_ADR: adr++; break;
2979 case TYPE_RET: ret++; break;
2980 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
2984 REPLACE_COUNT_DIST(stat_dist_stack, n);
2985 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
2986 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
2987 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
2989 #endif /* defined(REPLACE_STATISTICS) */
2992 /* debugging helpers **********************************************************/
2994 /* replace_replacement_point_println *******************************************
2996 Print replacement point info.
2999 rp...............the replacement point to print
3001 *******************************************************************************/
3003 #if !defined(NDEBUG)
3005 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3007 static char *replace_type_str[] = {
3017 void replace_replacement_point_println(rplpoint *rp, int depth)
3023 printf("(rplpoint *)NULL\n");
3027 for (j=0; j<depth; ++j)
3030 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3031 rp->id, (void*)rp,rp->pc,rp->callsize,
3032 replace_type_str[rp->type]);
3033 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3035 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3036 printf(" COUNTDOWN");
3037 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3039 printf(" parent:%p\n", (void*)rp->parent);
3040 for (j=0; j<depth; ++j)
3042 printf("ra:%d = [", rp->regalloccount);
3044 for (j=0; j<rp->regalloccount; ++j) {
3047 index = rp->regalloc[j].index;
3049 case RPLALLOC_STACK: printf("S"); break;
3050 case RPLALLOC_PARAM: printf("P"); break;
3051 case RPLALLOC_SYNC : printf("Y"); break;
3052 default: printf("%d", index);
3054 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3055 if (rp->regalloc[j].type == TYPE_RET) {
3056 printf("ret(L%03d)", rp->regalloc[j].regoff);
3059 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3064 for (j=0; j<depth; ++j)
3067 method_print(rp->method);
3071 #endif /* !defined(NDEBUG) */
3074 /* replace_show_replacement_points *********************************************
3076 Print replacement point info.
3079 code.............codeinfo whose replacement points should be printed.
3081 *******************************************************************************/
3083 #if !defined(NDEBUG)
3084 void replace_show_replacement_points(codeinfo *code)
3092 printf("(codeinfo *)NULL\n");
3096 printf("\treplacement points: %d\n",code->rplpointcount);
3098 printf("\ttotal allocations : %d\n",code->regalloccount);
3099 printf("\tsaved int regs : %d\n",code->savedintcount);
3100 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3101 printf("\tmemuse : %d\n",code->memuse);
3105 for (i=0; i<code->rplpointcount; ++i) {
3106 rp = code->rplpoints + i;
3109 parent = rp->parent;
3112 parent = parent->parent;
3114 replace_replacement_point_println(rp, depth);
3120 /* replace_executionstate_println **********************************************
3122 Print execution state
3125 es...............the execution state to print
3127 *******************************************************************************/
3129 #if !defined(NDEBUG)
3130 void replace_executionstate_println(executionstate_t *es)
3138 printf("(executionstate_t *)NULL\n");
3142 printf("executionstate_t:\n");
3143 printf("\tpc = %p",(void*)es->pc);
3144 printf(" sp = %p",(void*)es->sp);
3145 printf(" pv = %p\n",(void*)es->pv);
3146 #if defined(ENABLE_DISASSEMBLER)
3147 for (i=0; i<INT_REG_CNT; ++i) {
3152 #if SIZEOF_VOID_P == 8
3153 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3155 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3160 for (i=0; i<FLT_REG_CNT; ++i) {
3165 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3171 sp = (stackslot_t *) es->sp;
3176 methoddesc *md = es->code->m->parseddesc;
3177 slots = code_get_stack_frame_size(es->code);
3178 extraslots = 1 + md->memuse;
3185 printf("\tstack slots(+%d) at sp:", extraslots);
3186 for (i=0; i<slots+extraslots; ++i) {
3189 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3190 #ifdef HAS_4BYTE_STACKSLOT
3191 printf("%08lx",(unsigned long)*sp++);
3193 printf("%016llx",(unsigned long long)*sp++);
3195 printf("%c", (i >= slots) ? ')' : ' ');
3200 printf("\tcode: %p", (void*)es->code);
3201 if (es->code != NULL) {
3202 printf(" stackframesize=%d ", es->code->stackframesize);
3203 method_print(es->code->m);
3211 #if !defined(NDEBUG)
3212 static void java_value_print(s4 type, replace_val_t value)
3214 java_objectheader *obj;
3217 printf("%016llx",(unsigned long long) value.l);
3219 if (type < 0 || type > TYPE_RET)
3220 printf(" <INVALID TYPE:%d>", type);
3222 printf(" %s", show_jit_type_names[type]);
3224 if (type == TYPE_ADR && value.a != NULL) {
3227 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3229 if (obj->vftbl->class == class_java_lang_String) {
3231 u = javastring_toutf((java_lang_String *)obj, false);
3232 utf_display_printable_ascii(u);
3236 else if (type == TYPE_INT) {
3237 printf(" %ld", (long) value.i);
3239 else if (type == TYPE_LNG) {
3240 printf(" %lld", (long long) value.l);
3242 else if (type == TYPE_FLT) {
3243 printf(" %f", value.f);
3245 else if (type == TYPE_DBL) {
3246 printf(" %f", value.d);
3249 #endif /* !defined(NDEBUG) */
3252 #if !defined(NDEBUG)
3253 void replace_source_frame_println(sourceframe_t *frame)
3258 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3259 printf("\tNATIVE\n");
3260 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3261 printf("\tnativepc: %p\n", frame->nativepc);
3262 printf("\tframesize: %d\n", frame->nativeframesize);
3265 for (i=0; i<INT_REG_CNT; ++i) {
3266 if (nregdescint[i] == REG_SAV)
3267 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3271 for (i=0; i<FLT_REG_CNT; ++i) {
3272 if (nregdescfloat[i] == REG_SAV)
3273 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3281 method_println(frame->method);
3282 printf("\tid: %d\n", frame->id);
3283 printf("\ttype: %s\n", replace_type_str[frame->type]);
3286 if (frame->instance.a) {
3287 printf("\tinstance: ");
3288 java_value_print(TYPE_ADR, frame->instance);
3292 if (frame->javalocalcount) {
3293 printf("\tlocals (%d):\n",frame->javalocalcount);
3294 for (i=0; i<frame->javalocalcount; ++i) {
3295 t = frame->javalocaltype[i];
3296 if (t == TYPE_VOID) {
3297 printf("\tlocal[ %2d] = void\n",i);
3300 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3301 java_value_print(t, frame->javalocals[i]);
3308 if (frame->javastackdepth) {
3309 printf("\tstack (depth %d):\n",frame->javastackdepth);
3310 for (i=0; i<frame->javastackdepth; ++i) {
3311 t = frame->javastacktype[i];
3312 if (t == TYPE_VOID) {
3313 printf("\tstack[%2d] = void", i);
3316 printf("\tstack[%2d] = ",i);
3317 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3324 if (frame->syncslotcount) {
3325 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3326 for (i=0; i<frame->syncslotcount; ++i) {
3327 printf("\tslot[%2d] = ",i);
3328 #ifdef HAS_4BYTE_STACKSLOT
3329 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3331 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3337 if (frame->fromcode) {
3338 printf("\tfrom %p ", (void*)frame->fromcode);
3339 method_println(frame->fromcode->m);
3341 if (frame->tocode) {
3342 printf("\tto %p ", (void*)frame->tocode);
3343 method_println(frame->tocode->m);
3346 if (frame->fromrp) {
3347 printf("\tfrom replacement point:\n");
3348 replace_replacement_point_println(frame->fromrp, 2);
3351 printf("\tto replacement point:\n");
3352 replace_replacement_point_println(frame->torp, 2);
3357 #endif /* !defined(NDEBUG) */
3360 /* replace_sourcestate_println *************************************************
3365 ss...............the source state to print
3367 *******************************************************************************/
3369 #if !defined(NDEBUG)
3370 void replace_sourcestate_println(sourcestate_t *ss)
3373 sourceframe_t *frame;
3376 printf("(sourcestate_t *)NULL\n");
3380 printf("sourcestate_t:\n");
3382 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3383 printf(" frame %d:\n", i);
3384 replace_source_frame_println(frame);
3390 /* replace_sourcestate_println_short *******************************************
3392 Print a compact representation of the given source state.
3395 ss...............the source state to print
3397 *******************************************************************************/
3399 #if !defined(NDEBUG)
3400 void replace_sourcestate_println_short(sourcestate_t *ss)
3402 sourceframe_t *frame;
3404 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3407 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3408 printf("NATIVE (pc %p size %d) ",
3409 (void*)frame->nativepc, frame->nativeframesize);
3410 replace_stackframeinfo_println(frame->sfi);
3415 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3418 printf("%s", replace_type_str[frame->fromrp->type]);
3420 if (frame->torp && frame->torp->type != frame->fromrp->type)
3421 printf("->%s", replace_type_str[frame->torp->type]);
3423 if (frame->tocode != frame->fromcode)
3424 printf(" (%p->%p/%d) ",
3425 (void*) frame->fromcode, (void*) frame->tocode,
3428 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3430 method_println(frame->method);
3435 #if !defined(NDEBUG)
3436 static void replace_stackframeinfo_println(stackframeinfo *sfi)
3438 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3439 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3440 (void*)sfi->ra, (void*)sfi->xpc);
3443 method_println(sfi->method);
3450 * These are local overrides for various environment variables in Emacs.
3451 * Please do not remove this and leave it at the end of the file, where
3452 * Emacs will automagically detect them.
3453 * ---------------------------------------------------------------------
3456 * indent-tabs-mode: t
3460 * vim:noexpandtab:sw=4:ts=4: