1 /* src/vm/jit/replace.c - on-stack replacement of methods
3 Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
37 #if defined(ENABLE_GC_CACAO)
38 # include "mm/cacao-gc/gc.h"
41 #include "mm/memory.h"
43 #include "threads/threads-common.h"
45 #include "toolbox/logging.h"
47 #include "vm/stringlocal.h"
49 #include "vm/jit/abi.h"
50 #include "vm/jit/asmpart.h"
51 #include "vm/jit/disass.h"
52 #include "vm/jit/jit.h"
53 #include "vm/jit/md.h"
54 #include "vm/jit/methodheader.h"
55 #include "vm/jit/replace.h"
56 #include "vm/jit/show.h"
57 #include "vm/jit/stack.h"
59 #include "vmcore/options.h"
60 #include "vmcore/classcache.h"
63 #define REPLACE_PATCH_DYNAMIC_CALL
64 /*#define REPLACE_PATCH_ALL*/
66 #if defined(ENABLE_VMLOG)
67 #include <vmlog_cacao.h>
70 /*** architecture-dependent configuration *************************************/
72 /* first unset the macros (default) */
73 #undef REPLACE_RA_BETWEEN_FRAMES
74 #undef REPLACE_RA_TOP_OF_FRAME
75 #undef REPLACE_RA_LINKAGE_AREA
76 #undef REPLACE_LEAFMETHODS_RA_REGISTER
79 /* i386, x86_64 and m68k */
80 #if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
81 #define REPLACE_RA_BETWEEN_FRAMES
83 #elif defined(__ALPHA__)
84 #define REPLACE_RA_TOP_OF_FRAME
85 #define REPLACE_LEAFMETHODS_RA_REGISTER
86 #define REPLACE_REG_RA REG_RA
88 #elif defined(__POWERPC__)
89 #define REPLACE_RA_LINKAGE_AREA
90 #define REPLACE_LEAFMETHODS_RA_REGISTER
91 #define REPLACE_REG_RA REG_ITMP3 /* the execution state has the LR in itmp3 */
93 #elif defined(__S390__)
94 #define REPLACE_RA_TOP_OF_FRAME
95 #define REPLACE_REG_RA REG_ITMP3
99 /*** configuration of native stack slot size **********************************/
101 /* XXX this should be in md-abi.h files, probably */
103 #if defined(HAS_4BYTE_STACKSLOT)
104 #define SIZE_OF_STACKSLOT 4
105 #define STACK_SLOTS_PER_FLOAT 2
106 typedef u4 stackslot_t;
108 #define SIZE_OF_STACKSLOT 8
109 #define STACK_SLOTS_PER_FLOAT 1
110 typedef u8 stackslot_t;
114 /*** debugging ****************************************************************/
117 static void java_value_print(s4 type, replace_val_t value);
118 static void replace_stackframeinfo_println(stackframeinfo *sfi);
122 #define DOLOG(code) do{ if (opt_TraceReplacement > 1) { code; } } while(0)
123 #define DOLOG_SHORT(code) do{ if (opt_TraceReplacement > 0) { code; } } while(0)
126 #define DOLOG_SHORT(code)
130 /*** statistics ***************************************************************/
132 #define REPLACE_STATISTICS
134 #if defined(REPLACE_STATISTICS)
136 static int stat_replacements = 0;
137 static int stat_frames = 0;
138 static int stat_recompile = 0;
139 static int stat_staticpatch = 0;
140 static int stat_unroll_inline = 0;
141 static int stat_unroll_call = 0;
142 static int stat_dist_frames[20] = { 0 };
143 static int stat_dist_locals[20] = { 0 };
144 static int stat_dist_locals_adr[10] = { 0 };
145 static int stat_dist_locals_prim[10] = { 0 };
146 static int stat_dist_locals_ret[10] = { 0 };
147 static int stat_dist_locals_void[10] = { 0 };
148 static int stat_dist_stack[10] = { 0 };
149 static int stat_dist_stack_adr[10] = { 0 };
150 static int stat_dist_stack_prim[10] = { 0 };
151 static int stat_dist_stack_ret[10] = { 0 };
152 static int stat_methods = 0;
153 static int stat_rploints = 0;
154 static int stat_regallocs = 0;
155 static int stat_dist_method_rplpoints[20] = { 0 };
157 #define REPLACE_COUNT(cnt) (cnt)++
158 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
159 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
161 #define REPLACE_COUNT_DIST(array, val) \
163 int limit = (sizeof(array) / sizeof(int)) - 1; \
164 if ((val) < (limit)) (array)[val]++; \
165 else (array)[limit]++; \
168 static void replace_statistics_source_frame(sourceframe_t *frame);
172 #define REPLACE_COUNT(cnt)
173 #define REPLACE_COUNT_IF(cnt, cond)
174 #define REPLACE_COUNT_INC(cnt, inc)
175 #define REPLACE_COUNT_DIST(array, val)
177 #endif /* defined(REPLACE_STATISTICS) */
180 /*** constants used internally ************************************************/
182 #define TOP_IS_NORMAL 0
183 #define TOP_IS_ON_STACK 1
184 #define TOP_IS_IN_ITMP1 2
185 #define TOP_IS_VOID 3
188 /******************************************************************************/
189 /* PART I: Creating / freeing replacement points */
190 /******************************************************************************/
193 /* replace_create_replacement_point ********************************************
195 Create a replacement point.
198 jd...............current jitdata
199 iinfo............inlining info for the current position
200 rp...............pre-allocated (uninitialized) rplpoint
201 type.............RPLPOINT_TYPE constant
202 iptr.............current instruction
203 *pra.............current rplalloc pointer
204 javalocals.......the javalocals at the current point
205 stackvars........the stack variables at the current point
206 stackdepth.......the stack depth at the current point
207 paramcount.......number of parameters at the start of stackvars
210 *rpa.............points to the next free rplalloc
212 *******************************************************************************/
214 static void replace_create_replacement_point(jitdata *jd,
215 insinfo_inline *iinfo,
232 REPLACE_COUNT(stat_rploints);
234 rp->method = (iinfo) ? iinfo->method : jd->m;
235 rp->pc = NULL; /* set by codegen */
236 rp->callsize = 0; /* set by codegen */
240 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
242 /* XXX unify these two fields */
243 rp->parent = (iinfo) ? iinfo->rp : NULL;
245 /* store local allocation info of javalocals */
248 for (i = 0; i < rp->method->maxlocals; ++i) {
249 index = javalocals[i];
256 ra->flags = v->flags & (INMEMORY);
257 ra->regoff = v->vv.regoff;
261 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
269 /* store allocation info of java stack vars */
271 for (i = 0; i < stackdepth; ++i) {
272 v = VAR(stackvars[i]);
273 ra->flags = v->flags & (INMEMORY);
274 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
276 /* XXX how to handle locals on the stack containing returnAddresses? */
277 if (v->type == TYPE_RET) {
278 assert(stackvars[i] >= jd->localcount);
279 ra->regoff = v->vv.retaddr->nr;
282 ra->regoff = v->vv.regoff;
286 /* total number of allocations */
288 rp->regalloccount = ra - rp->regalloc;
294 /* replace_create_inline_start_replacement_point *******************************
296 Create an INLINE_START replacement point.
299 jd...............current jitdata
300 rp...............pre-allocated (uninitialized) rplpoint
301 iptr.............current instruction
302 *pra.............current rplalloc pointer
303 javalocals.......the javalocals at the current point
306 *rpa.............points to the next free rplalloc
309 the insinfo_inline * for the following inlined body
311 *******************************************************************************/
313 static insinfo_inline * replace_create_inline_start_replacement_point(
320 insinfo_inline *calleeinfo;
323 calleeinfo = iptr->sx.s23.s3.inlineinfo;
327 replace_create_replacement_point(jd, calleeinfo->parent, rp,
328 RPLPOINT_TYPE_INLINE, iptr, pra,
330 calleeinfo->stackvars, calleeinfo->stackvarscount,
331 calleeinfo->paramcount);
333 if (calleeinfo->synclocal != UNUSED) {
335 ra->index = RPLALLOC_SYNC;
336 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
337 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
347 /* replace_create_replacement_points *******************************************
349 Create the replacement points for the given code.
352 jd...............current jitdata, must not have any replacement points
355 code->rplpoints.......set to the list of replacement points
356 code->rplpointcount...number of replacement points
357 code->regalloc........list of allocation info
358 code->regalloccount...total length of allocation info list
359 code->globalcount.....number of global allocations at the
360 start of code->regalloc
363 true.............everything ok
364 false............an exception has been thrown
366 *******************************************************************************/
368 #define CLEAR_javalocals(array, method) \
370 for (i=0; i<(method)->maxlocals; ++i) \
371 (array)[i] = UNUSED; \
374 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
376 if ((array) != NULL) \
377 MCOPY((dest), (array), s4, (method)->maxlocals); \
379 CLEAR_javalocals((dest), (method)); \
382 #define COUNT_javalocals(array, method, counter) \
384 for (i=0; i<(method)->maxlocals; ++i) \
385 if ((array)[i] != UNUSED) \
389 bool replace_create_replacement_points(jitdata *jd)
407 insinfo_inline *iinfo;
410 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
414 REPLACE_COUNT(stat_methods);
416 /* get required compiler data */
421 /* assert that we wont overwrite already allocated data */
425 assert(code->rplpoints == NULL);
426 assert(code->rplpointcount == 0);
427 assert(code->regalloc == NULL);
428 assert(code->regalloccount == 0);
429 assert(code->globalcount == 0);
433 /* set codeinfo flags */
435 if (jd->isleafmethod)
436 CODE_SETFLAG_LEAFMETHOD(code);
438 /* in instance methods, we may need a rplpoint at the method entry */
440 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
441 if (!(m->flags & ACC_STATIC)) {
442 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
448 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
450 /* iterate over the basic block list to find replacement points */
455 javalocals = DMNEW(s4, jd->maxlocals);
457 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
461 if (bptr->flags < BBFINISHED)
464 /* get info about this block */
467 iinfo = bptr->inlineinfo;
469 /* initialize javalocals at the start of this block */
471 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
473 /* iterate over the instructions */
476 iend = iptr + bptr->icount;
480 for (; iptr != iend; ++iptr) {
482 #if defined(ENABLE_GC_CACAO)
484 md = iptr->sx.s23.s3.bte->md;
486 COUNT_javalocals(javalocals, m, alloccount);
487 alloccount += iptr->s1.argcount;
489 alloccount -= iinfo->throughcount;
493 case ICMD_INVOKESTATIC:
494 case ICMD_INVOKESPECIAL:
495 case ICMD_INVOKEVIRTUAL:
496 case ICMD_INVOKEINTERFACE:
497 INSTRUCTION_GET_METHODDESC(iptr, md);
499 COUNT_javalocals(javalocals, m, alloccount);
500 alloccount += iptr->s1.argcount;
502 alloccount -= iinfo->throughcount;
510 stack_javalocals_store(iptr, javalocals);
524 case ICMD_INLINE_START:
525 iinfo = iptr->sx.s23.s3.inlineinfo;
528 COUNT_javalocals(javalocals, m, alloccount);
529 alloccount += iinfo->stackvarscount;
530 if (iinfo->synclocal != UNUSED)
534 /* javalocals may be set at next block start, or now */
535 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
538 case ICMD_INLINE_BODY:
539 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
541 jl = iinfo->javalocals_start;
543 /* get the javalocals from the following block start */
545 jl = bptr->next->javalocals;
548 COUNT_javalocals(jl, m, alloccount);
551 case ICMD_INLINE_END:
552 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
553 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
554 iinfo = iptr->sx.s23.s3.inlineinfo;
556 if (iinfo->javalocals_end)
557 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
558 iinfo = iinfo->parent;
562 if (iptr == bptr->iinstr)
564 } /* end instruction loop */
566 /* create replacement points at targets of backward branches */
567 /* We only need the replacement point there, if there is no */
568 /* replacement point inside the block. */
570 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
571 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
572 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
576 if (test > startcount) {
577 /* we don't need an extra rplpoint */
578 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
582 alloccount += bptr->indepth;
583 if (bptr->inlineinfo)
584 alloccount -= bptr->inlineinfo->throughcount;
586 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
590 } /* end basicblock loop */
592 /* if no points were found, there's nothing to do */
597 /* allocate replacement point array and allocation array */
599 rplpoints = MNEW(rplpoint, count);
600 regalloc = MNEW(rplalloc, alloccount);
603 /* initialize replacement point structs */
607 /* XXX try to share code with the counting loop! */
609 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
612 if (bptr->flags < BBFINISHED)
615 /* get info about this block */
618 iinfo = bptr->inlineinfo;
620 /* initialize javalocals at the start of this block */
622 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
624 /* create replacement points at targets of backward branches */
626 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
628 i = (iinfo) ? iinfo->throughcount : 0;
629 replace_create_replacement_point(jd, iinfo, rp++,
630 bptr->type, bptr->iinstr, &ra,
631 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
633 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
634 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
637 /* iterate over the instructions */
640 iend = iptr + bptr->icount;
642 for (; iptr != iend; ++iptr) {
644 #if defined(ENABLE_GC_CACAO)
646 md = iptr->sx.s23.s3.bte->md;
648 i = (iinfo) ? iinfo->throughcount : 0;
649 replace_create_replacement_point(jd, iinfo, rp++,
650 RPLPOINT_TYPE_CALL, iptr, &ra,
651 javalocals, iptr->sx.s23.s2.args,
652 iptr->s1.argcount - i,
657 case ICMD_INVOKESTATIC:
658 case ICMD_INVOKESPECIAL:
659 case ICMD_INVOKEVIRTUAL:
660 case ICMD_INVOKEINTERFACE:
661 INSTRUCTION_GET_METHODDESC(iptr, md);
663 i = (iinfo) ? iinfo->throughcount : 0;
664 replace_create_replacement_point(jd, iinfo, rp++,
665 RPLPOINT_TYPE_CALL, iptr, &ra,
666 javalocals, iptr->sx.s23.s2.args,
667 iptr->s1.argcount - i,
676 stack_javalocals_store(iptr, javalocals);
684 replace_create_replacement_point(jd, iinfo, rp++,
685 RPLPOINT_TYPE_RETURN, iptr, &ra,
686 NULL, &(iptr->s1.varindex), 1, 0);
690 replace_create_replacement_point(jd, iinfo, rp++,
691 RPLPOINT_TYPE_RETURN, iptr, &ra,
695 case ICMD_INLINE_START:
696 iinfo = replace_create_inline_start_replacement_point(
697 jd, rp++, iptr, &ra, javalocals);
699 /* javalocals may be set at next block start, or now */
700 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
703 case ICMD_INLINE_BODY:
704 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
706 jl = iinfo->javalocals_start;
708 /* get the javalocals from the following block start */
710 jl = bptr->next->javalocals;
712 /* create a non-trappable rplpoint */
713 replace_create_replacement_point(jd, iinfo, rp++,
714 RPLPOINT_TYPE_BODY, iptr, &ra,
716 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
719 case ICMD_INLINE_END:
720 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
721 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
722 iinfo = iptr->sx.s23.s3.inlineinfo;
724 if (iinfo->javalocals_end)
725 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
726 iinfo = iinfo->parent;
729 } /* end instruction loop */
730 } /* end basicblock loop */
732 assert((rp - rplpoints) == count);
733 assert((ra - regalloc) == alloccount);
735 /* store the data in the codeinfo */
737 code->rplpoints = rplpoints;
738 code->rplpointcount = count;
739 code->regalloc = regalloc;
740 code->regalloccount = alloccount;
741 code->globalcount = 0;
742 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
743 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
744 #if defined(HAS_ADDRESS_REGISTER_FILE)
745 code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
747 code->memuse = rd->memuse;
748 code->stackframesize = jd->cd->stackframesize;
750 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
751 REPLACE_COUNT_INC(stat_regallocs, alloccount);
753 /* everything alright */
759 /* replace_free_replacement_points *********************************************
761 Free memory used by replacement points.
764 code.............codeinfo whose replacement points should be freed.
766 *******************************************************************************/
768 void replace_free_replacement_points(codeinfo *code)
773 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
776 MFREE(code->regalloc,rplalloc,code->regalloccount);
778 code->rplpoints = NULL;
779 code->rplpointcount = 0;
780 code->regalloc = NULL;
781 code->regalloccount = 0;
782 code->globalcount = 0;
786 /******************************************************************************/
787 /* PART II: Activating / deactivating replacement points */
788 /******************************************************************************/
791 /* replace_activate_replacement_points *****************************************
793 Activate the replacement points of the given compilation unit. When this
794 function returns, the replacement points are "armed", so each thread
795 reaching one of the points will enter the replacement mechanism.
798 code.............codeinfo of which replacement points should be
800 mappable.........if true, only mappable replacement points are
803 *******************************************************************************/
805 void replace_activate_replacement_points(codeinfo *code, bool mappable)
813 assert(code->savedmcode == NULL);
815 /* count trappable replacement points */
819 i = code->rplpointcount;
820 rp = code->rplpoints;
822 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
827 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
833 /* allocate buffer for saved machine code */
835 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
836 code->savedmcode = savedmcode;
837 savedmcode += count * REPLACEMENT_PATCH_SIZE;
839 /* activate trappable replacement points */
840 /* (in reverse order to handle overlapping points within basic blocks) */
842 i = code->rplpointcount;
843 rp = code->rplpoints + i;
845 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
847 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
852 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
855 DOLOG( printf("activate replacement point:\n");
856 replace_replacement_point_println(rp, 1); fflush(stdout); );
858 savedmcode -= REPLACEMENT_PATCH_SIZE;
860 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
861 md_patch_replacement_point(code, index, rp, savedmcode);
863 rp->flags |= RPLPOINT_FLAG_ACTIVE;
866 assert(savedmcode == code->savedmcode);
870 /* replace_deactivate_replacement_points ***************************************
872 Deactivate a replacement points in the given compilation unit.
873 When this function returns, the replacement points will be "un-armed",
874 that is a each thread reaching a point will just continue normally.
877 code.............the compilation unit
879 *******************************************************************************/
881 void replace_deactivate_replacement_points(codeinfo *code)
888 if (code->savedmcode == NULL) {
889 /* disarm countdown points by patching the branches */
891 i = code->rplpointcount;
892 rp = code->rplpoints;
894 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
895 == RPLPOINT_FLAG_COUNTDOWN)
898 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
905 assert(code->savedmcode != NULL);
906 savedmcode = code->savedmcode;
908 /* de-activate each trappable replacement point */
910 i = code->rplpointcount;
911 rp = code->rplpoints;
914 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
919 DOLOG( printf("deactivate replacement point:\n");
920 replace_replacement_point_println(rp, 1); fflush(stdout); );
922 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
923 md_patch_replacement_point(code, -1, rp, savedmcode);
926 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
928 savedmcode += REPLACEMENT_PATCH_SIZE;
931 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
933 /* free saved machine code */
935 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
936 code->savedmcode = NULL;
940 /******************************************************************************/
941 /* PART III: The replacement mechanism */
942 /******************************************************************************/
945 /* replace_read_value **********************************************************
947 Read a value with the given allocation from the execution state.
950 es...............execution state
951 ra...............allocation
952 javaval..........where to put the value
955 *javaval.........the value
957 *******************************************************************************/
959 static void replace_read_value(executionstate_t *es,
961 replace_val_t *javaval)
963 if (ra->flags & INMEMORY) {
964 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
965 #ifdef HAS_4BYTE_STACKSLOT
966 if (IS_2_WORD_TYPE(ra->type)) {
967 javaval->l = *(u8*)(es->sp + ra->regoff);
971 javaval->p = *(ptrint*)(es->sp + ra->regoff);
972 #ifdef HAS_4BYTE_STACKSLOT
977 /* allocated register */
978 if (IS_FLT_DBL_TYPE(ra->type)) {
979 javaval->d = es->fltregs[ra->regoff];
981 if (ra->type == TYPE_FLT)
982 javaval->f = javaval->d;
984 #if defined(HAS_ADDRESS_REGISTER_FILE)
985 else if (IS_ADR_TYPE(ra->type)) {
986 javaval->p = es->adrregs[ra->regoff];
990 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
991 if (ra->type == TYPE_LNG) {
992 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
993 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
996 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
997 javaval->p = es->intregs[ra->regoff];
1003 /* replace_write_value *********************************************************
1005 Write a value to the given allocation in the execution state.
1008 es...............execution state
1009 ra...............allocation
1010 *javaval.........the value
1012 *******************************************************************************/
1014 static void replace_write_value(executionstate_t *es,
1016 replace_val_t *javaval)
1018 if (ra->flags & INMEMORY) {
1019 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1020 #ifdef HAS_4BYTE_STACKSLOT
1021 if (IS_2_WORD_TYPE(ra->type)) {
1022 *(u8*)(es->sp + ra->regoff) = javaval->l;
1026 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1027 #ifdef HAS_4BYTE_STACKSLOT
1032 /* allocated register */
1035 es->fltregs[ra->regoff] = (double) javaval->f;
1038 es->fltregs[ra->regoff] = javaval->d;
1040 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1042 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1043 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1046 #if defined(HAS_ADDRESS_REGISTER_FILE)
1048 es->adrregs[ra->regoff] = javaval->p;
1051 es->intregs[ra->regoff] = javaval->p;
1057 /* replace_read_executionstate *************************************************
1059 Read the given executions state and translate it to a source frame.
1062 ss...............the source state
1065 ss->frames.......set to new frame
1068 returns the new frame
1070 *******************************************************************************/
1072 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1074 sourceframe_t *frame;
1076 frame = DNEW(sourceframe_t);
1077 MZERO(frame, sourceframe_t, 1);
1079 frame->down = ss->frames;
1086 /* replace_read_executionstate *************************************************
1088 Read the given executions state and translate it to a source frame.
1091 rp...............replacement point at which `es` was taken
1092 es...............execution state
1093 ss...............where to put the source state
1096 *ss..............the source state derived from the execution state
1098 *******************************************************************************/
1100 static s4 replace_normalize_type_map[] = {
1101 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1102 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1103 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1104 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1105 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1106 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1107 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1111 static void replace_read_executionstate(rplpoint *rp,
1112 executionstate_t *es,
1121 sourceframe_t *frame;
1124 stackslot_t *basesp;
1126 code = code_find_codeinfo_for_pc(rp->pc);
1128 topslot = TOP_IS_NORMAL;
1132 sp = (stackslot_t *) es->sp;
1134 /* in some cases the top stack slot is passed in REG_ITMP1 */
1136 if (rp->type == BBTYPE_EXH) {
1137 topslot = TOP_IS_IN_ITMP1;
1140 /* calculate base stack pointer */
1142 basesp = sp + code->stackframesize;
1144 /* create the source frame */
1146 frame = replace_new_sourceframe(ss);
1147 frame->method = rp->method;
1149 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1150 frame->type = replace_normalize_type_map[rp->type];
1152 frame->fromcode = code;
1154 /* read local variables */
1156 count = m->maxlocals;
1157 frame->javalocalcount = count;
1158 frame->javalocals = DMNEW(replace_val_t, count);
1159 frame->javalocaltype = DMNEW(u1, count);
1161 /* mark values as undefined */
1162 for (i=0; i<count; ++i) {
1163 #if !defined(NDEBUG)
1164 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1166 frame->javalocaltype[i] = TYPE_VOID;
1169 /* some entries in the intregs array are not meaningful */
1170 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1171 #if !defined(NDEBUG)
1172 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1174 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1176 #endif /* !defined(NDEBUG) */
1178 /* read javalocals */
1180 count = rp->regalloccount;
1183 while (count && (i = ra->index) >= 0) {
1184 assert(i < m->maxlocals);
1185 frame->javalocaltype[i] = ra->type;
1186 if (ra->type == TYPE_RET)
1187 frame->javalocals[i].i = ra->regoff;
1189 replace_read_value(es, ra, frame->javalocals + i);
1194 /* read instance, if this is the first rplpoint */
1196 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1197 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1199 /* we are at the start of the method body, so if local 0 is set, */
1200 /* it is the instance. */
1201 if (frame->javalocaltype[0] == TYPE_ADR)
1202 frame->instance = frame->javalocals[0];
1207 md = rp->method->parseddesc;
1209 assert(md->paramcount >= 1);
1210 instra.type = TYPE_ADR;
1211 instra.regoff = md->params[0].regoff;
1212 if (md->params[0].inmemory) {
1213 instra.flags = INMEMORY;
1214 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1219 replace_read_value(es, &instra, &(frame->instance));
1222 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1224 /* read stack slots */
1226 frame->javastackdepth = count;
1227 frame->javastack = DMNEW(replace_val_t, count);
1228 frame->javastacktype = DMNEW(u1, count);
1230 #if !defined(NDEBUG)
1231 /* mark values as undefined */
1232 for (i=0; i<count; ++i) {
1233 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1234 frame->javastacktype[i] = TYPE_VOID;
1236 #endif /* !defined(NDEBUG) */
1240 /* the first stack slot is special in SBR and EXH blocks */
1242 if (topslot == TOP_IS_ON_STACK) {
1245 assert(ra->index == RPLALLOC_STACK);
1246 assert(ra->type == TYPE_ADR);
1247 frame->javastack[i].p = sp[-1];
1248 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1253 else if (topslot == TOP_IS_IN_ITMP1) {
1256 assert(ra->index == RPLALLOC_STACK);
1257 assert(ra->type == TYPE_ADR);
1258 frame->javastack[i].p = es->intregs[REG_ITMP1];
1259 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1264 else if (topslot == TOP_IS_VOID) {
1267 assert(ra->index == RPLALLOC_STACK);
1268 frame->javastack[i].l = 0;
1269 frame->javastacktype[i] = TYPE_VOID;
1275 /* read remaining stack slots */
1277 for (; count--; ra++) {
1278 if (ra->index == RPLALLOC_SYNC) {
1279 assert(rp->type == RPLPOINT_TYPE_INLINE);
1281 /* only read synchronization slots when traversing an inline point */
1284 sourceframe_t *calleeframe = frame->down;
1285 assert(calleeframe);
1286 assert(calleeframe->syncslotcount == 0);
1287 assert(calleeframe->syncslots == NULL);
1289 calleeframe->syncslotcount = 1;
1290 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1291 replace_read_value(es,ra,calleeframe->syncslots);
1294 frame->javastackdepth--;
1298 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1300 /* do not read parameters of calls down the call chain */
1302 if (!topframe && ra->index == RPLALLOC_PARAM) {
1303 frame->javastackdepth--;
1306 if (ra->type == TYPE_RET)
1307 frame->javastack[i].i = ra->regoff;
1309 replace_read_value(es,ra,frame->javastack + i);
1310 frame->javastacktype[i] = ra->type;
1317 /* replace_write_executionstate ************************************************
1319 Translate the given source state into an execution state.
1322 rp...............replacement point for which execution state should be
1324 es...............where to put the execution state
1325 ss...............the given source state
1328 *es..............the execution state derived from the source state
1330 *******************************************************************************/
1332 static void replace_write_executionstate(rplpoint *rp,
1333 executionstate_t *es,
1342 sourceframe_t *frame;
1345 stackslot_t *basesp;
1347 code = code_find_codeinfo_for_pc(rp->pc);
1349 topslot = TOP_IS_NORMAL;
1351 /* pop a source frame */
1355 ss->frames = frame->down;
1357 /* calculate stack pointer */
1359 sp = (stackslot_t *) es->sp;
1361 basesp = sp + code->stackframesize;
1363 /* in some cases the top stack slot is passed in REG_ITMP1 */
1365 if (rp->type == BBTYPE_EXH) {
1366 topslot = TOP_IS_IN_ITMP1;
1369 /* write javalocals */
1372 count = rp->regalloccount;
1374 while (count && (i = ra->index) >= 0) {
1375 assert(i < m->maxlocals);
1376 assert(i < frame->javalocalcount);
1377 assert(ra->type == frame->javalocaltype[i]);
1378 if (ra->type == TYPE_RET) {
1379 /* XXX assert that it matches this rplpoint */
1382 replace_write_value(es, ra, frame->javalocals + i);
1387 /* write stack slots */
1391 /* the first stack slot is special in SBR and EXH blocks */
1393 if (topslot == TOP_IS_ON_STACK) {
1396 assert(ra->index == RPLALLOC_STACK);
1397 assert(i < frame->javastackdepth);
1398 assert(frame->javastacktype[i] == TYPE_ADR);
1399 sp[-1] = frame->javastack[i].p;
1404 else if (topslot == TOP_IS_IN_ITMP1) {
1407 assert(ra->index == RPLALLOC_STACK);
1408 assert(i < frame->javastackdepth);
1409 assert(frame->javastacktype[i] == TYPE_ADR);
1410 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1415 else if (topslot == TOP_IS_VOID) {
1418 assert(ra->index == RPLALLOC_STACK);
1419 assert(i < frame->javastackdepth);
1420 assert(frame->javastacktype[i] == TYPE_VOID);
1426 /* write remaining stack slots */
1428 for (; count--; ra++) {
1429 if (ra->index == RPLALLOC_SYNC) {
1430 assert(rp->type == RPLPOINT_TYPE_INLINE);
1432 /* only write synchronization slots when traversing an inline point */
1435 assert(frame->down);
1436 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1437 assert(frame->down->syncslots != NULL);
1439 replace_write_value(es,ra,frame->down->syncslots);
1444 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1446 /* do not write parameters of calls down the call chain */
1448 if (!topframe && ra->index == RPLALLOC_PARAM) {
1452 assert(i < frame->javastackdepth);
1453 assert(ra->type == frame->javastacktype[i]);
1454 if (ra->type == TYPE_RET) {
1455 /* XXX assert that it matches this rplpoint */
1458 replace_write_value(es,ra,frame->javastack + i);
1470 /* replace_pop_activation_record ***********************************************
1472 Peel a stack frame from the execution state.
1474 *** This function imitates the effects of the method epilog ***
1475 *** and returning from the method call. ***
1478 es...............execution state
1479 frame............source frame, receives synchronization slots
1482 *es..............the execution state after popping the stack frame
1484 *******************************************************************************/
1486 u1* replace_pop_activation_record(executionstate_t *es,
1487 sourceframe_t *frame)
1495 stackslot_t *basesp;
1501 /* read the return address */
1503 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1504 if (CODE_IS_LEAFMETHOD(es->code))
1505 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1508 ra = md_stacktrace_get_returnaddress(es->sp,
1509 SIZE_OF_STACKSLOT * es->code->stackframesize);
1511 DOLOG( printf("return address: %p\n", (void*)ra); );
1515 /* calculate the base of the stack frame */
1517 sp = (stackslot_t *) es->sp;
1518 basesp = sp + es->code->stackframesize;
1520 /* read slots used for synchronization */
1522 assert(frame->syncslotcount == 0);
1523 assert(frame->syncslots == NULL);
1524 count = code_get_sync_slot_count(es->code);
1525 frame->syncslotcount = count;
1526 frame->syncslots = DMNEW(replace_val_t, count);
1527 for (i=0; i<count; ++i) {
1528 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1531 /* restore return address, if part of frame */
1533 #if defined(REPLACE_RA_TOP_OF_FRAME)
1534 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1535 if (!CODE_IS_LEAFMETHOD(es->code))
1537 es->intregs[REPLACE_REG_RA] = *--basesp;
1538 #endif /* REPLACE_RA_TOP_OF_FRAME */
1540 #if defined(REPLACE_RA_LINKAGE_AREA)
1541 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1542 if (!CODE_IS_LEAFMETHOD(es->code))
1544 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1545 #endif /* REPLACE_RA_LINKAGE_AREA */
1547 /* restore saved int registers */
1550 for (i=0; i<es->code->savedintcount; ++i) {
1551 while (nregdescint[--reg] != REG_SAV)
1553 es->intregs[reg] = *--basesp;
1556 /* restore saved flt registers */
1560 for (i=0; i<es->code->savedfltcount; ++i) {
1561 while (nregdescfloat[--reg] != REG_SAV)
1563 basesp -= STACK_SLOTS_PER_FLOAT;
1564 es->fltregs[reg] = *(double*)basesp;
1567 #if defined(HAS_ADDRESS_REGISTER_FILE)
1568 /* restore saved adr registers */
1571 for (i=0; i<es->code->savedadrcount; ++i) {
1572 while (nregdescadr[--reg] != REG_SAV)
1574 es->adrregs[reg] = *--basesp;
1578 /* adjust the stackpointer */
1580 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1582 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1583 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1586 /* Set the new pc. Subtract one so we do not hit the replacement point */
1587 /* of the instruction following the call, if there is one. */
1591 /* find the new codeinfo */
1593 pv = md_codegen_get_pv_from_pc(ra);
1595 DOLOG( printf("PV = %p\n", (void*) pv); );
1597 if (pv == NULL) /* XXX can this really happen? */
1600 code = *(codeinfo **)(pv + CodeinfoPointer);
1602 DOLOG( printf("CODE = %p\n", (void*) code); );
1604 /* return NULL if we reached native code */
1609 /* in debugging mode clobber non-saved registers */
1611 #if !defined(NDEBUG)
1613 for (i=0; i<INT_REG_CNT; ++i)
1614 if ((nregdescint[i] != REG_SAV)
1616 && (i != REPLACE_REG_RA)
1619 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1620 for (i=0; i<FLT_REG_CNT; ++i)
1621 if (nregdescfloat[i] != REG_SAV)
1622 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1623 # if defined(HAS_ADDRESS_REGISTER_FILE)
1624 for (i=0; i<ADR_REG_CNT; ++i)
1625 if (nregdescadr[i] != REG_SAV)
1626 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1628 #endif /* !defined(NDEBUG) */
1630 return (code) ? ra : NULL;
1634 /* replace_patch_method_pointer ************************************************
1636 Patch a method pointer (may be in code, data segment, vftbl, or interface
1640 mpp..............address of the method pointer to patch
1641 entrypoint.......the new entrypoint of the method
1642 kind.............kind of call to patch, used only for debugging
1644 *******************************************************************************/
1646 static void replace_patch_method_pointer(methodptr *mpp,
1647 methodptr entrypoint,
1650 #if !defined(NDEBUG)
1655 DOLOG( printf("patch method pointer from: %p to %p\n",
1656 (void*) *mpp, (void*)entrypoint); );
1658 #if !defined(NDEBUG)
1659 oldcode = *(codeinfo **)((u1*)(*mpp) + CodeinfoPointer);
1660 newcode = *(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer);
1662 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1663 method_println(oldcode->m);
1664 printf("\t with %p ", (void*) newcode);
1665 method_println(newcode->m); );
1667 assert(oldcode->m == newcode->m);
1670 /* write the new entrypoint */
1672 *mpp = (methodptr) entrypoint;
1676 /* replace_patch_class *********************************************************
1678 Patch a method in the given class.
1681 vftbl............vftbl of the class
1682 m................the method to patch
1683 oldentrypoint....the old entrypoint to replace
1684 entrypoint.......the new entrypoint
1686 *******************************************************************************/
1688 void replace_patch_class(vftbl_t *vftbl,
1697 /* patch the vftbl of the class */
1699 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1703 /* patch the interface tables */
1705 assert(oldentrypoint);
1707 for (i=0; i < vftbl->interfacetablelength; ++i) {
1708 mpp = vftbl->interfacetable[-i];
1709 mppend = mpp + vftbl->interfacevftbllength[i];
1710 for (; mpp != mppend; ++mpp)
1711 if (*mpp == oldentrypoint) {
1712 replace_patch_method_pointer(mpp, entrypoint, "interface");
1718 /* replace_patch_class_hierarchy ***********************************************
1720 Patch a method in all loaded classes.
1723 m................the method to patch
1724 oldentrypoint....the old entrypoint to replace
1725 entrypoint.......the new entrypoint
1727 *******************************************************************************/
1729 struct replace_patch_data_t {
1735 #define CODEINFO_OF_CODE(entrypoint) \
1736 (*(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer))
1738 #define METHOD_OF_CODE(entrypoint) \
1739 (CODEINFO_OF_CODE(entrypoint)->m)
1741 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1743 vftbl_t *vftbl = c->vftbl;
1746 && vftbl->vftbllength > pd->m->vftblindex
1747 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1748 && METHOD_OF_CODE(vftbl->table[pd->m->vftblindex]) == pd->m)
1750 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1754 void replace_patch_class_hierarchy(methodinfo *m,
1758 struct replace_patch_data_t pd;
1761 pd.oldentrypoint = oldentrypoint;
1762 pd.entrypoint = entrypoint;
1764 DOLOG_SHORT( printf("patching class hierarchy: ");
1765 method_println(m); );
1767 classcache_foreach_loaded_class(
1768 (classcache_foreach_functionptr_t) &replace_patch_callback,
1773 /* replace_patch_future_calls **************************************************
1775 Analyse a call site and depending on the kind of call patch the call, the
1776 virtual function table, or the interface table.
1779 ra...............return address pointing after the call site
1780 callerframe......source frame of the caller
1781 calleeframe......source frame of the callee, must have been mapped
1783 *******************************************************************************/
1785 void replace_patch_future_calls(u1 *ra,
1786 sourceframe_t *callerframe,
1787 sourceframe_t *calleeframe)
1790 methodptr entrypoint;
1791 methodptr oldentrypoint;
1794 codeinfo *calleecode;
1795 methodinfo *calleem;
1796 java_objectheader *obj;
1800 assert(callerframe->down == calleeframe);
1802 /* get the new codeinfo and the method that shall be entered */
1804 calleecode = calleeframe->tocode;
1807 calleem = calleeframe->method;
1808 assert(calleem == calleecode->m);
1810 entrypoint = (methodptr) calleecode->entrypoint;
1812 /* check if we are at an method entry rplpoint at the innermost frame */
1814 atentry = (calleeframe->down == NULL)
1815 && !(calleem->flags & ACC_STATIC)
1816 && (calleeframe->fromrp->id == 0); /* XXX */
1818 /* get the position to patch, in case it was a statically bound call */
1820 sfi.pv = callerframe->fromcode->entrypoint;
1821 patchpos = md_get_method_patch_address(ra, &sfi, NULL);
1823 if (patchpos == NULL) {
1824 /* the call was dispatched dynamically */
1826 /* we can only patch such calls if we are at the entry point */
1831 assert((calleem->flags & ACC_STATIC) == 0);
1833 oldentrypoint = calleeframe->fromcode->entrypoint;
1835 /* we need to know the instance */
1837 if (!calleeframe->instance.a) {
1838 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1839 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1845 obj = calleeframe->instance.a;
1848 assert(vftbl->class->vftbl == vftbl);
1850 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1852 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1855 /* the call was statically bound */
1857 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1862 /* replace_push_activation_record **********************************************
1864 Push a stack frame onto the execution state.
1866 *** This function imitates the effects of a call and the ***
1867 *** method prolog of the callee. ***
1870 es...............execution state
1871 rpcall...........the replacement point at the call site
1872 callerframe......source frame of the caller, or NULL for creating the
1874 calleeframe......source frame of the callee, must have been mapped
1877 *es..............the execution state after pushing the stack frame
1879 *******************************************************************************/
1881 void replace_push_activation_record(executionstate_t *es,
1883 sourceframe_t *callerframe,
1884 sourceframe_t *calleeframe)
1889 stackslot_t *basesp;
1892 codeinfo *calleecode;
1895 assert(!rpcall || callerframe);
1896 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1897 assert(!rpcall || rpcall == callerframe->torp);
1898 assert(calleeframe);
1899 assert(!callerframe || calleeframe == callerframe->down);
1901 /* the compilation unit we are entering */
1903 calleecode = calleeframe->tocode;
1906 /* calculate the return address */
1909 ra = rpcall->pc + rpcall->callsize;
1911 ra = es->pc + 1 /* XXX this is ugly */;
1913 /* write the return address */
1915 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1916 es->sp -= SIZE_OF_STACKSLOT;
1918 *((stackslot_t *)es->sp) = (stackslot_t) ra;
1919 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1921 #if defined(REPLACE_REG_RA)
1922 es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1925 /* we move into a new code unit */
1927 es->code = calleecode;
1929 /* set the new pc XXX not needed? */
1931 es->pc = calleecode->entrypoint;
1933 /* build the stackframe */
1935 DOLOG( printf("building stackframe of %d words at %p\n",
1936 calleecode->stackframesize, (void*)es->sp); );
1938 sp = (stackslot_t *) es->sp;
1941 sp -= calleecode->stackframesize;
1944 /* in debug mode, invalidate stack frame first */
1946 /* XXX may not invalidate linkage area used by native code! */
1947 #if !defined(NDEBUG) && 0
1948 for (i=0; i<(basesp - sp); ++i) {
1949 sp[i] = 0xdeaddeadU;
1953 /* save the return address register */
1955 #if defined(REPLACE_RA_TOP_OF_FRAME)
1956 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1957 if (!CODE_IS_LEAFMETHOD(calleecode))
1959 *--basesp = (ptrint) ra;
1960 #endif /* REPLACE_RA_TOP_OF_FRAME */
1962 #if defined(REPLACE_RA_LINKAGE_AREA)
1963 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1964 if (!CODE_IS_LEAFMETHOD(calleecode))
1966 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1967 #endif /* REPLACE_RA_LINKAGE_AREA */
1969 /* save int registers */
1972 for (i=0; i<calleecode->savedintcount; ++i) {
1973 while (nregdescint[--reg] != REG_SAV)
1975 *--basesp = es->intregs[reg];
1977 /* XXX may not clobber saved regs used by native code! */
1978 #if !defined(NDEBUG) && 0
1979 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1983 /* save flt registers */
1987 for (i=0; i<calleecode->savedfltcount; ++i) {
1988 while (nregdescfloat[--reg] != REG_SAV)
1990 basesp -= STACK_SLOTS_PER_FLOAT;
1991 *(double*)basesp = es->fltregs[reg];
1993 /* XXX may not clobber saved regs used by native code! */
1994 #if !defined(NDEBUG) && 0
1995 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1999 #if defined(HAS_ADDRESS_REGISTER_FILE)
2000 /* save adr registers */
2003 for (i=0; i<calleecode->savedadrcount; ++i) {
2004 while (nregdescadr[--reg] != REG_SAV)
2006 *--basesp = es->adrregs[reg];
2008 /* XXX may not clobber saved regs used by native code! */
2009 #if !defined(NDEBUG) && 0
2010 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
2015 /* write slots used for synchronization */
2017 count = code_get_sync_slot_count(calleecode);
2018 assert(count == calleeframe->syncslotcount);
2019 for (i=0; i<count; ++i) {
2020 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2025 es->pv = calleecode->entrypoint;
2027 /* redirect future invocations */
2029 if (callerframe && rpcall) {
2030 #if defined(REPLACE_PATCH_ALL)
2031 if (rpcall->type == callerframe->fromrp->type)
2033 if (rpcall == callerframe->fromrp)
2035 replace_patch_future_calls(ra, callerframe, calleeframe);
2040 /* replace_find_replacement_point **********************************************
2042 Find the replacement point in the given code corresponding to the
2043 position given in the source frame.
2046 code.............the codeinfo in which to search the rplpoint
2047 frame............the source frame defining the position to look for
2048 parent...........parent replacement point to match
2051 the replacement point
2053 *******************************************************************************/
2055 rplpoint * replace_find_replacement_point(codeinfo *code,
2056 sourceframe_t *frame,
2069 DOLOG( printf("searching replacement point for:\n");
2070 replace_source_frame_println(frame); );
2074 DOLOG( printf("code = %p\n", (void*)code); );
2076 rp = code->rplpoints;
2077 i = code->rplpointcount;
2079 if (rp->id == frame->id && rp->method == frame->method
2080 && rp->parent == parent
2081 && replace_normalize_type_map[rp->type] == frame->type)
2083 /* check if returnAddresses match */
2084 /* XXX optimize: only do this if JSRs in method */
2085 DOLOG( printf("checking match for:");
2086 replace_replacement_point_println(rp, 1); fflush(stdout); );
2089 for (j = rp->regalloccount; j--; ++ra) {
2090 if (ra->type == TYPE_RET) {
2091 if (ra->index == RPLALLOC_STACK) {
2092 assert(stacki < frame->javastackdepth);
2093 if (frame->javastack[stacki].i != ra->regoff)
2098 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2099 if (frame->javalocals[ra->index].i != ra->regoff)
2112 #if !defined(NDEBUG)
2113 printf("candidate replacement points were:\n");
2114 rp = code->rplpoints;
2115 i = code->rplpointcount;
2117 replace_replacement_point_println(rp, 1);
2121 vm_abort("no matching replacement point found");
2122 return NULL; /* NOT REACHED */
2126 /* replace_find_replacement_point_for_pc ***************************************
2128 Find the nearest replacement point at or before the given PC.
2131 code.............compilation unit the PC is in
2132 pc...............the machine code PC
2135 the replacement point found, or
2136 NULL if no replacement point was found
2138 *******************************************************************************/
2140 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2146 DOLOG( printf("searching for rp in %p ", (void*)code);
2147 method_println(code->m);
2148 printf("PC = %p\n", (void*)pc); );
2152 rp = code->rplpoints;
2153 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2154 DOLOG( replace_replacement_point_println(rp, 2); );
2159 assert(found == NULL || found->pc + found->callsize >= pc);
2165 /* replace_pop_native_frame ****************************************************
2167 Unroll a native frame in the execution state and create a source frame
2171 es...............current execution state
2172 ss...............the current source state
2173 sfi..............stackframeinfo for the native frame
2176 es...............execution state after unrolling the native frame
2177 ss...............gets the added native source frame
2179 *******************************************************************************/
2181 static void replace_pop_native_frame(executionstate_t *es,
2183 stackframeinfo *sfi)
2185 sourceframe_t *frame;
2191 frame = replace_new_sourceframe(ss);
2195 /* remember pc and size of native frame */
2197 frame->nativepc = es->pc;
2198 frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2199 assert(frame->nativeframesize >= 0);
2201 /* remember values of saved registers */
2204 for (i=0; i<INT_REG_CNT; ++i) {
2205 if (nregdescint[i] == REG_SAV)
2206 frame->nativesavint[j++] = es->intregs[i];
2210 for (i=0; i<FLT_REG_CNT; ++i) {
2211 if (nregdescfloat[i] == REG_SAV)
2212 frame->nativesavflt[j++] = es->fltregs[i];
2215 #if defined(HAS_ADDRESS_REGISTER_FILE)
2217 for (i=0; i<ADR_REG_CNT; ++i) {
2218 if (nregdescadr[i] == REG_SAV)
2219 frame->nativesavadr[j++] = es->adrregs[i];
2223 /* restore saved registers */
2225 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2227 for (i=0; i<INT_REG_CNT; ++i) {
2228 if (nregdescint[i] == REG_SAV)
2229 es->intregs[i] = sfi->intregs[j++];
2232 /* XXX we don't have them, yet, in the sfi, so clear them */
2234 for (i=0; i<INT_REG_CNT; ++i) {
2235 if (nregdescint[i] == REG_SAV)
2240 /* XXX we don't have float registers in the sfi, so clear them */
2242 for (i=0; i<FLT_REG_CNT; ++i) {
2243 if (nregdescfloat[i] == REG_SAV)
2244 es->fltregs[i] = 0.0;
2247 #if defined(HAS_ADDRESS_REGISTER_FILE)
2248 # if defined(ENABLE_GC_CACAO)
2250 for (i=0; i<ADR_REG_CNT; ++i) {
2251 if (nregdescadr[i] == REG_SAV)
2252 es->adrregs[i] = sfi->adrregs[j++];
2255 for (i=0; i<ADR_REG_CNT; ++i) {
2256 if (nregdescadr[i] == REG_SAV)
2262 /* restore pv, pc, and sp */
2264 if (sfi->pv == NULL) {
2265 /* frame of a native function call */
2266 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2271 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2274 /* find the new codeinfo */
2276 DOLOG( printf("PV = %p\n", (void*) es->pv); );
2278 assert(es->pv != NULL);
2280 code = *(codeinfo **)(es->pv + CodeinfoPointer);
2282 DOLOG( printf("CODE = %p\n", (void*) code); );
2288 /* replace_push_native_frame ***************************************************
2290 Rebuild a native frame onto the execution state and remove its source frame.
2292 Note: The native frame is "rebuild" by setting fields like PC and stack
2293 pointer in the execution state accordingly. Values in the
2294 stackframeinfo may be modified, but the actual stack frame of the
2295 native code is not touched.
2298 es...............current execution state
2299 ss...............the current source state
2302 es...............execution state after re-rolling the native frame
2303 ss...............the native source frame is removed
2305 *******************************************************************************/
2307 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2309 sourceframe_t *frame;
2315 DOLOG( printf("pushing native frame\n"); );
2317 /* remove the frame from the source state */
2321 assert(REPLACE_IS_NATIVE_FRAME(frame));
2323 ss->frames = frame->down;
2325 /* assert that the native frame has not moved */
2327 assert(es->sp == frame->sfi->sp);
2329 /* update saved registers in the stackframeinfo */
2331 #if defined(ENABLE_GC_CACAO)
2333 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2334 for (i=0; i<INT_REG_CNT; ++i) {
2335 if (nregdescint[i] == REG_SAV)
2336 frame->sfi->intregs[j++] = es->intregs[i];
2339 for (i=0; i<ADR_REG_CNT; ++i) {
2340 if (nregdescadr[i] == REG_SAV)
2341 frame->sfi->adrregs[j++] = es->adrregs[i];
2345 /* XXX leave float registers untouched here */
2348 /* restore saved registers */
2351 for (i=0; i<INT_REG_CNT; ++i) {
2352 if (nregdescint[i] == REG_SAV)
2353 es->intregs[i] = frame->nativesavint[j++];
2357 for (i=0; i<FLT_REG_CNT; ++i) {
2358 if (nregdescfloat[i] == REG_SAV)
2359 es->fltregs[i] = frame->nativesavflt[j++];
2362 #if defined(HAS_ADDRESS_REGISTER_FILE)
2364 for (i=0; i<ADR_REG_CNT; ++i) {
2365 if (nregdescadr[i] == REG_SAV)
2366 es->adrregs[i] = frame->nativesavadr[j++];
2370 /* skip the native frame on the machine stack */
2372 es->sp -= frame->nativeframesize;
2374 /* set the pc the next frame must return to */
2376 es->pc = frame->nativepc;
2380 /* replace_recover_source_state ************************************************
2382 Recover the source state from the given replacement point and execution
2386 rp...............replacement point that has been reached, if any
2387 sfi..............stackframeinfo, if called from native code
2388 es...............execution state at the replacement point rp
2393 *******************************************************************************/
2395 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2396 stackframeinfo *sfi,
2397 executionstate_t *es)
2402 #if defined(REPLACE_STATISTICS)
2406 /* create the source frame structure in dump memory */
2408 ss = DNEW(sourcestate_t);
2411 /* each iteration of the loop recovers one source frame */
2418 DOLOG( replace_executionstate_println(es); );
2420 /* if we are not at a replacement point, it is a native frame */
2423 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2426 replace_pop_native_frame(es, ss, sfi);
2429 if (es->code == NULL)
2432 goto after_machine_frame;
2435 /* read the values for this source frame from the execution state */
2437 DOLOG( printf("recovering source state for%s:\n",
2438 (ss->frames == NULL) ? " TOPFRAME" : "");
2439 replace_replacement_point_println(rp, 1); );
2441 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2443 #if defined(ENABLE_VMLOG)
2444 vmlog_cacao_unrol_method(ss->frames->method);
2447 #if defined(REPLACE_STATISTICS)
2448 REPLACE_COUNT(stat_frames);
2450 replace_statistics_source_frame(ss->frames);
2453 /* in locked areas (below native frames), identity map the frame */
2456 ss->frames->torp = ss->frames->fromrp;
2457 ss->frames->tocode = ss->frames->fromcode;
2460 /* unroll to the next (outer) frame */
2463 /* this frame is in inlined code */
2465 DOLOG( printf("INLINED!\n"); );
2469 assert(rp->type == RPLPOINT_TYPE_INLINE);
2470 REPLACE_COUNT(stat_unroll_inline);
2473 /* this frame had been called at machine-level. pop it. */
2475 DOLOG( printf("UNWIND\n"); );
2477 ra = replace_pop_activation_record(es, ss->frames);
2479 DOLOG( printf("REACHED NATIVE CODE\n"); );
2483 #if !defined(ENABLE_GC_CACAO)
2484 break; /* XXX remove to activate native frames */
2489 /* find the replacement point at the call site */
2491 after_machine_frame:
2492 rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2495 vm_abort("could not find replacement point while unrolling call");
2497 DOLOG( printf("found replacement point.\n");
2498 replace_replacement_point_println(rp, 1); );
2500 assert(rp->type == RPLPOINT_TYPE_CALL);
2501 REPLACE_COUNT(stat_unroll_call);
2503 } /* end loop over source frames */
2505 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2511 /* replace_map_source_state ****************************************************
2513 Map each source frame in the given source state to a target replacement
2514 point and compilation unit. If no valid code is available for a source
2515 frame, it is (re)compiled.
2518 ss...............the source state
2521 ss...............the source state, modified: The `torp` and `tocode`
2522 fields of each source frame are set.
2525 true.............everything went ok
2526 false............an exception has been thrown
2528 *******************************************************************************/
2530 static bool replace_map_source_state(sourcestate_t *ss)
2532 sourceframe_t *frame;
2535 rplpoint *parent; /* parent of inlined rplpoint */
2536 #if defined(REPLACE_STATISTICS)
2543 /* iterate over the source frames from outermost to innermost */
2545 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2547 /* XXX skip native frames */
2549 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2554 /* map frames which are not already mapped */
2556 if (frame->tocode) {
2557 code = frame->tocode;
2562 assert(frame->torp == NULL);
2564 if (parent == NULL) {
2565 /* find code for this frame */
2567 #if defined(REPLACE_STATISTICS)
2568 oldcode = frame->method->code;
2570 /* request optimization of hot methods and their callers */
2572 if (frame->method->hitcountdown < 0
2573 || (frame->down && frame->down->method->hitcountdown < 0))
2574 jit_request_optimization(frame->method);
2576 code = jit_get_current_code(frame->method);
2579 return false; /* exception */
2581 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2586 /* map this frame */
2588 rp = replace_find_replacement_point(code, frame, parent);
2590 frame->tocode = code;
2594 if (rp->type == RPLPOINT_TYPE_CALL) {
2607 /* replace_map_source_state_identity *******************************************
2609 Map each source frame in the given source state to the same replacement
2610 point and compilation unit it was derived from. This is mainly used for
2614 ss...............the source state
2617 ss...............the source state, modified: The `torp` and `tocode`
2618 fields of each source frame are set.
2620 *******************************************************************************/
2622 #if defined(ENABLE_GC_CACAO)
2623 static void replace_map_source_state_identity(sourcestate_t *ss)
2625 sourceframe_t *frame;
2627 /* iterate over the source frames from outermost to innermost */
2629 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2631 /* skip native frames */
2633 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2637 /* map frames using the identity mapping */
2639 if (frame->tocode) {
2640 assert(frame->tocode == frame->fromcode);
2641 assert(frame->torp == frame->fromrp);
2643 assert(frame->tocode == NULL);
2644 assert(frame->torp == NULL);
2645 frame->tocode = frame->fromcode;
2646 frame->torp = frame->fromrp;
2653 /* replace_build_execution_state_intern ****************************************
2655 Build an execution state for the given (mapped) source state.
2657 !!! CAUTION: This function rewrites the machine stack !!!
2659 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2662 ss...............the source state. Must have been mapped by
2663 replace_map_source_state before.
2664 es...............the base execution state on which to build
2667 *es..............the new execution state
2669 *******************************************************************************/
2671 void replace_build_execution_state_intern(sourcestate_t *ss,
2672 executionstate_t *es)
2675 sourceframe_t *prevframe;
2682 while (ss->frames) {
2684 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2685 prevframe = ss->frames;
2686 replace_push_native_frame(es, ss);
2692 if (parent == NULL) {
2693 /* create a machine-level stack frame */
2695 DOLOG( printf("pushing activation record for:\n");
2696 if (rp) replace_replacement_point_println(rp, 1);
2697 else printf("\tfirst frame\n"); );
2699 replace_push_activation_record(es, rp, prevframe, ss->frames);
2701 DOLOG( replace_executionstate_println(es); );
2704 rp = ss->frames->torp;
2707 DOLOG( printf("creating execution state for%s:\n",
2708 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2709 replace_replacement_point_println(ss->frames->fromrp, 1);
2710 replace_replacement_point_println(rp, 1); );
2712 es->code = ss->frames->tocode;
2713 prevframe = ss->frames;
2715 #if defined(ENABLE_VMLOG)
2716 vmlog_cacao_rerol_method(ss->frames->method);
2719 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2721 DOLOG( replace_executionstate_println(es); );
2723 if (rp->type == RPLPOINT_TYPE_CALL) {
2734 /* replace_build_execution_state ***********************************************
2736 This function contains the final phase of replacement. It builds the new
2737 execution state, releases dump memory, and returns to the calling
2738 assembler function which finishes replacement.
2740 NOTE: This function is called from asm_replacement_in, with the stack
2741 pointer at the start of the safe stack area.
2743 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2745 CAUTION: This function and its children must not use a lot of stack!
2746 There are only REPLACE_SAFESTACK_SIZE bytes of C stack
2750 st...............the safestack contained the necessary data
2752 *******************************************************************************/
2754 void replace_build_execution_state(replace_safestack_t *st)
2756 replace_build_execution_state_intern(st->ss, &(st->es));
2758 DOLOG( replace_executionstate_println(&(st->es)); );
2760 /* release dump area */
2762 dump_release(st->dumpsize);
2764 /* new code is entered after returning */
2766 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2770 /* replace_alloc_safestack *****************************************************
2772 Allocate a safe stack area to use during the final phase of replacement.
2773 The returned area is not initialized. This must be done by the caller.
2776 a newly allocated replace_safestack_t *
2778 *******************************************************************************/
2780 static replace_safestack_t *replace_alloc_safestack()
2783 replace_safestack_t *st;
2785 mem = MNEW(u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2787 st = (replace_safestack_t *) ((ptrint)(mem + REPLACE_STACK_ALIGNMENT - 1)
2788 & ~(REPLACE_STACK_ALIGNMENT - 1));
2790 #if !defined(NDEBUG)
2791 memset(st, 0xa5, sizeof(replace_safestack_t));
2800 /* replace_free_safestack ******************************************************
2802 Free the given safestack structure, making a copy of the contained
2803 execution state before freeing it.
2805 NOTE: This function is called from asm_replacement_in.
2808 st...............the safestack to free
2809 tmpes............where to copy the execution state to
2812 *tmpes...........receives a copy of st->es
2814 *******************************************************************************/
2816 void replace_free_safestack(replace_safestack_t *st, executionstate_t *tmpes)
2820 /* copy the executionstate_t to the temporary location */
2824 /* get the memory address to free */
2828 /* destroy memory (in debug mode) */
2830 #if !defined(NDEBUG)
2831 memset(st, 0xa5, sizeof(replace_safestack_t));
2834 /* free the safe stack struct */
2836 MFREE(mem, u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2840 /* replace_me_wrapper **********************************************************
2844 *******************************************************************************/
2846 bool replace_me_wrapper(u1 *pc)
2850 executionstate_t es;
2852 /* search the codeinfo for the given PC */
2854 code = code_find_codeinfo_for_pc(pc);
2857 /* search for a replacement point at the given PC */
2860 rp = replace_find_replacement_point_for_pc(code, pc);
2861 assert(rp == NULL || rp->pc == pc);
2867 for (i=0,rp2=code->rplpoints; i<code->rplpointcount; i++,rp2++) {
2874 /* check if the replacement point is active */
2876 if (rp != NULL && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
2878 /*md_replace_executionstate_read(&es, context);*/
2880 replace_me(rp, &es);
2889 /* replace_me ******************************************************************
2891 This function is called by asm_replacement_out when a thread reaches
2892 a replacement point. `replace_me` must map the execution state to the
2893 target replacement point and let execution continue there.
2895 This function never returns!
2898 rp...............replacement point that has been reached
2899 es...............execution state read by asm_replacement_out
2901 *******************************************************************************/
2903 void replace_me(rplpoint *rp, executionstate_t *es)
2905 stackframeinfo *sfi;
2907 sourceframe_t *frame;
2910 replace_safestack_t *safestack;
2911 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2912 threadobject *thread;
2916 es->code = code_find_codeinfo_for_pc(rp->pc);
2918 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2919 stat_replacements, (void*)THREADOBJECT,
2921 method_println(es->code->m); );
2923 DOLOG( replace_replacement_point_println(rp, 1);
2924 replace_executionstate_println(es); );
2926 REPLACE_COUNT(stat_replacements);
2928 /* mark start of dump memory area */
2930 dumpsize = dump_size();
2932 /* get the stackframeinfo for the current thread */
2934 sfi = STACKFRAMEINFO;
2936 /* recover source state */
2938 ss = replace_recover_source_state(rp, sfi, es);
2940 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2941 /* if there is a collection pending, we assume the replacement point should
2942 suspend this thread */
2946 thread = THREADOBJECT;
2948 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2950 /* map the sourcestate using the identity mapping */
2951 replace_map_source_state_identity(ss);
2953 /* since we enter the same method again, we turn off rps now */
2954 /* XXX michi: can we really do this? what if the rp was active before
2955 we activated it for the gc? */
2958 frame = frame->down;
2959 replace_deactivate_replacement_points(frame->tocode);
2961 /* remember executionstate and sourcestate for this thread */
2962 GC_EXECUTIONSTATE = es;
2963 GC_SOURCESTATE = ss;
2965 /* really suspend this thread now (PC = 0) */
2966 threads_suspend_ack(NULL, NULL);
2968 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2971 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2973 /* map the source state */
2975 if (!replace_map_source_state(ss))
2976 vm_abort("exception during method replacement");
2978 DOLOG( replace_sourcestate_println(ss); );
2980 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2982 /* avoid infinite loops by self-replacement */
2986 frame = frame->down;
2988 if (frame->torp == origrp) {
2990 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2992 replace_deactivate_replacement_points(frame->tocode);
2995 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2999 /* write execution state of new code */
3001 DOLOG( replace_executionstate_println(es); );
3003 /* allocate a safe stack area and copy all needed data there */
3005 safestack = replace_alloc_safestack();
3007 safestack->es = *es;
3009 safestack->dumpsize = dumpsize;
3011 /* call the assembler code for the last phase of replacement */
3013 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
3014 asm_replacement_in(&(safestack->es), safestack);
3017 abort(); /* NOT REACHED */
3021 /******************************************************************************/
3022 /* NOTE: Stuff specific to the exact GC is below. */
3023 /******************************************************************************/
3025 #if defined(ENABLE_GC_CACAO)
3026 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
3028 stackframeinfo *sfi;
3029 executionstate_t *es;
3032 /* get the stackframeinfo of this thread */
3033 assert(thread == THREADOBJECT);
3034 sfi = STACKFRAMEINFO;
3036 /* create the execution state */
3037 es = DNEW(executionstate_t);
3040 es->pv = 0; /* since we are in a native, PV is invalid! */
3041 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
3043 /* we assume we are in a native (no replacement point)! */
3044 ss = replace_recover_source_state(NULL, sfi, es);
3046 /* map the sourcestate using the identity mapping */
3047 replace_map_source_state_identity(ss);
3049 /* remember executionstate and sourcestate for this thread */
3050 GC_EXECUTIONSTATE = es;
3051 GC_SOURCESTATE = ss;
3056 /******************************************************************************/
3057 /* NOTE: No important code below. */
3058 /******************************************************************************/
3061 /* statistics *****************************************************************/
3063 #if defined(REPLACE_STATISTICS)
3064 static void print_freq(FILE *file,int *array,int limit)
3069 for (i=0; i<limit; ++i)
3071 sum += array[limit];
3072 for (i=0; i<limit; ++i) {
3074 fprintf(file," %3d: %8d (cum %3d%%)\n",
3075 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3077 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3079 #endif /* defined(REPLACE_STATISTICS) */
3082 #if defined(REPLACE_STATISTICS)
3084 #define REPLACE_PRINT_DIST(name, array) \
3085 printf(" " name " distribution:\n"); \
3086 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3088 void replace_print_statistics(void)
3090 printf("replacement statistics:\n");
3091 printf(" # of replacements: %d\n", stat_replacements);
3092 printf(" # of frames: %d\n", stat_frames);
3093 printf(" # of recompilations: %d\n", stat_recompile);
3094 printf(" patched static calls:%d\n", stat_staticpatch);
3095 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3096 printf(" unrolled calls: %d\n", stat_unroll_call);
3097 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3098 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3099 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3100 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3101 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3102 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3103 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3104 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3105 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3106 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3108 printf(" # of methods: %d\n", stat_methods);
3109 printf(" # of replacement points: %d\n", stat_rploints);
3110 printf(" # of regallocs: %d\n", stat_regallocs);
3111 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3112 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3113 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3117 #endif /* defined(REPLACE_STATISTICS) */
3120 #if defined(REPLACE_STATISTICS)
3121 static void replace_statistics_source_frame(sourceframe_t *frame)
3130 for (i=0; i<frame->javalocalcount; ++i) {
3131 switch (frame->javalocaltype[i]) {
3132 case TYPE_ADR: adr++; break;
3133 case TYPE_RET: ret++; break;
3134 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3135 case TYPE_VOID: vd++; break;
3140 REPLACE_COUNT_DIST(stat_dist_locals, n);
3141 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3142 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3143 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3144 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3145 adr = ret = prim = n = 0;
3146 for (i=0; i<frame->javastackdepth; ++i) {
3147 switch (frame->javastacktype[i]) {
3148 case TYPE_ADR: adr++; break;
3149 case TYPE_RET: ret++; break;
3150 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3154 REPLACE_COUNT_DIST(stat_dist_stack, n);
3155 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3156 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3157 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3159 #endif /* defined(REPLACE_STATISTICS) */
3162 /* debugging helpers **********************************************************/
3164 /* replace_replacement_point_println *******************************************
3166 Print replacement point info.
3169 rp...............the replacement point to print
3171 *******************************************************************************/
3173 #if !defined(NDEBUG)
3175 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3177 static char *replace_type_str[] = {
3187 void replace_replacement_point_println(rplpoint *rp, int depth)
3193 printf("(rplpoint *)NULL\n");
3197 for (j=0; j<depth; ++j)
3200 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3201 rp->id, (void*)rp,rp->pc,rp->callsize,
3202 replace_type_str[rp->type]);
3203 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3205 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3206 printf(" COUNTDOWN");
3207 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3209 printf(" parent:%p\n", (void*)rp->parent);
3210 for (j=0; j<depth; ++j)
3212 printf("ra:%d = [", rp->regalloccount);
3214 for (j=0; j<rp->regalloccount; ++j) {
3217 index = rp->regalloc[j].index;
3219 case RPLALLOC_STACK: printf("S"); break;
3220 case RPLALLOC_PARAM: printf("P"); break;
3221 case RPLALLOC_SYNC : printf("Y"); break;
3222 default: printf("%d", index);
3224 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3225 if (rp->regalloc[j].type == TYPE_RET) {
3226 printf("ret(L%03d)", rp->regalloc[j].regoff);
3229 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3234 for (j=0; j<depth; ++j)
3237 method_print(rp->method);
3241 #endif /* !defined(NDEBUG) */
3244 /* replace_show_replacement_points *********************************************
3246 Print replacement point info.
3249 code.............codeinfo whose replacement points should be printed.
3251 *******************************************************************************/
3253 #if !defined(NDEBUG)
3254 void replace_show_replacement_points(codeinfo *code)
3262 printf("(codeinfo *)NULL\n");
3266 printf("\treplacement points: %d\n",code->rplpointcount);
3268 printf("\ttotal allocations : %d\n",code->regalloccount);
3269 printf("\tsaved int regs : %d\n",code->savedintcount);
3270 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3271 #if defined(HAS_ADDRESS_REGISTER_FILE)
3272 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3274 printf("\tmemuse : %d\n",code->memuse);
3278 for (i=0; i<code->rplpointcount; ++i) {
3279 rp = code->rplpoints + i;
3282 parent = rp->parent;
3285 parent = parent->parent;
3287 replace_replacement_point_println(rp, depth);
3293 /* replace_executionstate_println **********************************************
3295 Print execution state
3298 es...............the execution state to print
3300 *******************************************************************************/
3302 #if !defined(NDEBUG)
3303 void replace_executionstate_println(executionstate_t *es)
3311 printf("(executionstate_t *)NULL\n");
3315 printf("executionstate_t:\n");
3316 printf("\tpc = %p",(void*)es->pc);
3317 printf(" sp = %p",(void*)es->sp);
3318 printf(" pv = %p\n",(void*)es->pv);
3319 #if defined(ENABLE_DISASSEMBLER)
3320 for (i=0; i<INT_REG_CNT; ++i) {
3325 #if SIZEOF_VOID_P == 8
3326 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3328 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3333 for (i=0; i<FLT_REG_CNT; ++i) {
3338 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3342 # if defined(HAS_ADDRESS_REGISTER_FILE)
3343 for (i=0; i<ADR_REG_CNT; ++i) {
3348 printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
3355 sp = (stackslot_t *) es->sp;
3360 methoddesc *md = es->code->m->parseddesc;
3361 slots = es->code->stackframesize;
3362 extraslots = 1 + md->memuse;
3369 printf("\tstack slots(+%d) at sp:", extraslots);
3370 for (i=0; i<slots+extraslots; ++i) {
3373 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3374 #ifdef HAS_4BYTE_STACKSLOT
3375 printf("%08lx",(unsigned long)*sp++);
3377 printf("%016llx",(unsigned long long)*sp++);
3379 printf("%c", (i >= slots) ? ')' : ' ');
3384 printf("\tcode: %p", (void*)es->code);
3385 if (es->code != NULL) {
3386 printf(" stackframesize=%d ", es->code->stackframesize);
3387 method_print(es->code->m);
3395 #if !defined(NDEBUG)
3396 static void java_value_print(s4 type, replace_val_t value)
3398 java_objectheader *obj;
3401 printf("%016llx",(unsigned long long) value.l);
3403 if (type < 0 || type > TYPE_RET)
3404 printf(" <INVALID TYPE:%d>", type);
3406 printf(" %s", show_jit_type_names[type]);
3408 if (type == TYPE_ADR && value.a != NULL) {
3411 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3413 if (obj->vftbl->class == class_java_lang_String) {
3415 u = javastring_toutf(obj, false);
3416 utf_display_printable_ascii(u);
3420 else if (type == TYPE_INT) {
3421 printf(" %ld", (long) value.i);
3423 else if (type == TYPE_LNG) {
3424 printf(" %lld", (long long) value.l);
3426 else if (type == TYPE_FLT) {
3427 printf(" %f", value.f);
3429 else if (type == TYPE_DBL) {
3430 printf(" %f", value.d);
3433 #endif /* !defined(NDEBUG) */
3436 #if !defined(NDEBUG)
3437 void replace_source_frame_println(sourceframe_t *frame)
3442 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3443 printf("\tNATIVE\n");
3444 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3445 printf("\tnativepc: %p\n", frame->nativepc);
3446 printf("\tframesize: %d\n", frame->nativeframesize);
3449 for (i=0; i<INT_REG_CNT; ++i) {
3450 if (nregdescint[i] == REG_SAV)
3451 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3455 for (i=0; i<FLT_REG_CNT; ++i) {
3456 if (nregdescfloat[i] == REG_SAV)
3457 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3465 method_println(frame->method);
3466 printf("\tid: %d\n", frame->id);
3467 printf("\ttype: %s\n", replace_type_str[frame->type]);
3470 if (frame->instance.a) {
3471 printf("\tinstance: ");
3472 java_value_print(TYPE_ADR, frame->instance);
3476 if (frame->javalocalcount) {
3477 printf("\tlocals (%d):\n",frame->javalocalcount);
3478 for (i=0; i<frame->javalocalcount; ++i) {
3479 t = frame->javalocaltype[i];
3480 if (t == TYPE_VOID) {
3481 printf("\tlocal[ %2d] = void\n",i);
3484 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3485 java_value_print(t, frame->javalocals[i]);
3492 if (frame->javastackdepth) {
3493 printf("\tstack (depth %d):\n",frame->javastackdepth);
3494 for (i=0; i<frame->javastackdepth; ++i) {
3495 t = frame->javastacktype[i];
3496 if (t == TYPE_VOID) {
3497 printf("\tstack[%2d] = void", i);
3500 printf("\tstack[%2d] = ",i);
3501 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3508 if (frame->syncslotcount) {
3509 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3510 for (i=0; i<frame->syncslotcount; ++i) {
3511 printf("\tslot[%2d] = ",i);
3512 #ifdef HAS_4BYTE_STACKSLOT
3513 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3515 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3521 if (frame->fromcode) {
3522 printf("\tfrom %p ", (void*)frame->fromcode);
3523 method_println(frame->fromcode->m);
3525 if (frame->tocode) {
3526 printf("\tto %p ", (void*)frame->tocode);
3527 method_println(frame->tocode->m);
3530 if (frame->fromrp) {
3531 printf("\tfrom replacement point:\n");
3532 replace_replacement_point_println(frame->fromrp, 2);
3535 printf("\tto replacement point:\n");
3536 replace_replacement_point_println(frame->torp, 2);
3541 #endif /* !defined(NDEBUG) */
3544 /* replace_sourcestate_println *************************************************
3549 ss...............the source state to print
3551 *******************************************************************************/
3553 #if !defined(NDEBUG)
3554 void replace_sourcestate_println(sourcestate_t *ss)
3557 sourceframe_t *frame;
3560 printf("(sourcestate_t *)NULL\n");
3564 printf("sourcestate_t:\n");
3566 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3567 printf(" frame %d:\n", i);
3568 replace_source_frame_println(frame);
3574 /* replace_sourcestate_println_short *******************************************
3576 Print a compact representation of the given source state.
3579 ss...............the source state to print
3581 *******************************************************************************/
3583 #if !defined(NDEBUG)
3584 void replace_sourcestate_println_short(sourcestate_t *ss)
3586 sourceframe_t *frame;
3588 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3591 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3592 printf("NATIVE (pc %p size %d) ",
3593 (void*)frame->nativepc, frame->nativeframesize);
3594 replace_stackframeinfo_println(frame->sfi);
3599 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3602 printf("%s", replace_type_str[frame->fromrp->type]);
3604 if (frame->torp && frame->torp->type != frame->fromrp->type)
3605 printf("->%s", replace_type_str[frame->torp->type]);
3607 if (frame->tocode != frame->fromcode)
3608 printf(" (%p->%p/%d) ",
3609 (void*) frame->fromcode, (void*) frame->tocode,
3612 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3614 method_println(frame->method);
3619 #if !defined(NDEBUG)
3620 static void replace_stackframeinfo_println(stackframeinfo *sfi)
3622 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3623 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3624 (void*)sfi->ra, (void*)sfi->xpc);
3627 method_println(sfi->method);
3634 * These are local overrides for various environment variables in Emacs.
3635 * Please do not remove this and leave it at the end of the file, where
3636 * Emacs will automagically detect them.
3637 * ---------------------------------------------------------------------
3640 * indent-tabs-mode: t
3644 * vim:noexpandtab:sw=4:ts=4: