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_new_sourceframe *****************************************************
1059 Allocate a new source frame and insert it at the front of the frame list.
1062 ss...............the source state
1065 ss->frames.......set to new frame (the new head of the frame list).
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 a source frame from the given executions state.
1089 The new source frame is pushed to the front of the frame list of the
1093 rp...............replacement point at which `es` was taken
1094 es...............execution state
1095 ss...............the source state to add the source frame to
1096 topframe.........true, if the first (top-most) source frame on the
1100 *ss..............the source state with the newly created source frame
1103 *******************************************************************************/
1105 static s4 replace_normalize_type_map[] = {
1106 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1107 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1108 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1109 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1110 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1111 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1112 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1116 static void replace_read_executionstate(rplpoint *rp,
1117 executionstate_t *es,
1126 sourceframe_t *frame;
1129 stackslot_t *basesp;
1131 code = code_find_codeinfo_for_pc(rp->pc);
1133 topslot = TOP_IS_NORMAL;
1137 sp = (stackslot_t *) es->sp;
1139 /* in some cases the top stack slot is passed in REG_ITMP1 */
1141 if (rp->type == BBTYPE_EXH) {
1142 topslot = TOP_IS_IN_ITMP1;
1145 /* calculate base stack pointer */
1147 basesp = sp + code->stackframesize;
1149 /* create the source frame */
1151 frame = replace_new_sourceframe(ss);
1152 frame->method = rp->method;
1154 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1155 frame->type = replace_normalize_type_map[rp->type];
1157 frame->fromcode = code;
1159 /* read local variables */
1161 count = m->maxlocals;
1162 frame->javalocalcount = count;
1163 frame->javalocals = DMNEW(replace_val_t, count);
1164 frame->javalocaltype = DMNEW(u1, count);
1166 /* mark values as undefined */
1167 for (i=0; i<count; ++i) {
1168 #if !defined(NDEBUG)
1169 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1171 frame->javalocaltype[i] = TYPE_VOID;
1174 /* some entries in the intregs array are not meaningful */
1175 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1176 #if !defined(NDEBUG)
1177 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1179 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1181 #endif /* !defined(NDEBUG) */
1183 /* read javalocals */
1185 count = rp->regalloccount;
1188 while (count && (i = ra->index) >= 0) {
1189 assert(i < m->maxlocals);
1190 frame->javalocaltype[i] = ra->type;
1191 if (ra->type == TYPE_RET)
1192 frame->javalocals[i].i = ra->regoff;
1194 replace_read_value(es, ra, frame->javalocals + i);
1199 /* read instance, if this is the first rplpoint */
1201 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1202 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1204 /* we are at the start of the method body, so if local 0 is set, */
1205 /* it is the instance. */
1206 if (frame->javalocaltype[0] == TYPE_ADR)
1207 frame->instance = frame->javalocals[0];
1212 md = rp->method->parseddesc;
1214 assert(md->paramcount >= 1);
1215 instra.type = TYPE_ADR;
1216 instra.regoff = md->params[0].regoff;
1217 if (md->params[0].inmemory) {
1218 instra.flags = INMEMORY;
1219 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1224 replace_read_value(es, &instra, &(frame->instance));
1227 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1229 /* read stack slots */
1231 frame->javastackdepth = count;
1232 frame->javastack = DMNEW(replace_val_t, count);
1233 frame->javastacktype = DMNEW(u1, count);
1235 #if !defined(NDEBUG)
1236 /* mark values as undefined */
1237 for (i=0; i<count; ++i) {
1238 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1239 frame->javastacktype[i] = TYPE_VOID;
1241 #endif /* !defined(NDEBUG) */
1245 /* the first stack slot is special in SBR and EXH blocks */
1247 if (topslot == TOP_IS_ON_STACK) {
1250 assert(ra->index == RPLALLOC_STACK);
1251 assert(ra->type == TYPE_ADR);
1252 frame->javastack[i].p = sp[-1];
1253 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1258 else if (topslot == TOP_IS_IN_ITMP1) {
1261 assert(ra->index == RPLALLOC_STACK);
1262 assert(ra->type == TYPE_ADR);
1263 frame->javastack[i].p = es->intregs[REG_ITMP1];
1264 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1269 else if (topslot == TOP_IS_VOID) {
1272 assert(ra->index == RPLALLOC_STACK);
1273 frame->javastack[i].l = 0;
1274 frame->javastacktype[i] = TYPE_VOID;
1280 /* read remaining stack slots */
1282 for (; count--; ra++) {
1283 if (ra->index == RPLALLOC_SYNC) {
1284 assert(rp->type == RPLPOINT_TYPE_INLINE);
1286 /* only read synchronization slots when traversing an inline point */
1289 sourceframe_t *calleeframe = frame->down;
1290 assert(calleeframe);
1291 assert(calleeframe->syncslotcount == 0);
1292 assert(calleeframe->syncslots == NULL);
1294 calleeframe->syncslotcount = 1;
1295 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1296 replace_read_value(es,ra,calleeframe->syncslots);
1299 frame->javastackdepth--;
1303 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1305 /* do not read parameters of calls down the call chain */
1307 if (!topframe && ra->index == RPLALLOC_PARAM) {
1308 frame->javastackdepth--;
1311 if (ra->type == TYPE_RET)
1312 frame->javastack[i].i = ra->regoff;
1314 replace_read_value(es,ra,frame->javastack + i);
1315 frame->javastacktype[i] = ra->type;
1322 /* replace_write_executionstate ************************************************
1324 Pop a source frame from the front of the frame list of the given source state
1325 and write its values into the execution state.
1328 rp...............replacement point for which execution state should be
1330 es...............the execution state to modify
1331 ss...............the given source state
1332 topframe.........true, if this is the last (top-most) source frame to be
1336 *es..............the execution state derived from the source state
1338 *******************************************************************************/
1340 static void replace_write_executionstate(rplpoint *rp,
1341 executionstate_t *es,
1350 sourceframe_t *frame;
1353 stackslot_t *basesp;
1355 code = code_find_codeinfo_for_pc(rp->pc);
1357 topslot = TOP_IS_NORMAL;
1359 /* pop a source frame */
1363 ss->frames = frame->down;
1365 /* calculate stack pointer */
1367 sp = (stackslot_t *) es->sp;
1369 basesp = sp + code->stackframesize;
1371 /* in some cases the top stack slot is passed in REG_ITMP1 */
1373 if (rp->type == BBTYPE_EXH) {
1374 topslot = TOP_IS_IN_ITMP1;
1377 /* write javalocals */
1380 count = rp->regalloccount;
1382 while (count && (i = ra->index) >= 0) {
1383 assert(i < m->maxlocals);
1384 assert(i < frame->javalocalcount);
1385 assert(ra->type == frame->javalocaltype[i]);
1386 if (ra->type == TYPE_RET) {
1387 /* XXX assert that it matches this rplpoint */
1390 replace_write_value(es, ra, frame->javalocals + i);
1395 /* write stack slots */
1399 /* the first stack slot is special in SBR and EXH blocks */
1401 if (topslot == TOP_IS_ON_STACK) {
1404 assert(ra->index == RPLALLOC_STACK);
1405 assert(i < frame->javastackdepth);
1406 assert(frame->javastacktype[i] == TYPE_ADR);
1407 sp[-1] = frame->javastack[i].p;
1412 else if (topslot == TOP_IS_IN_ITMP1) {
1415 assert(ra->index == RPLALLOC_STACK);
1416 assert(i < frame->javastackdepth);
1417 assert(frame->javastacktype[i] == TYPE_ADR);
1418 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1423 else if (topslot == TOP_IS_VOID) {
1426 assert(ra->index == RPLALLOC_STACK);
1427 assert(i < frame->javastackdepth);
1428 assert(frame->javastacktype[i] == TYPE_VOID);
1434 /* write remaining stack slots */
1436 for (; count--; ra++) {
1437 if (ra->index == RPLALLOC_SYNC) {
1438 assert(rp->type == RPLPOINT_TYPE_INLINE);
1440 /* only write synchronization slots when traversing an inline point */
1443 assert(frame->down);
1444 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1445 assert(frame->down->syncslots != NULL);
1447 replace_write_value(es,ra,frame->down->syncslots);
1452 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1454 /* do not write parameters of calls down the call chain */
1456 if (!topframe && ra->index == RPLALLOC_PARAM) {
1460 assert(i < frame->javastackdepth);
1461 assert(ra->type == frame->javastacktype[i]);
1462 if (ra->type == TYPE_RET) {
1463 /* XXX assert that it matches this rplpoint */
1466 replace_write_value(es,ra,frame->javastack + i);
1478 /* replace_pop_activation_record ***********************************************
1480 Peel a stack frame from the execution state.
1482 *** This function imitates the effects of the method epilog ***
1483 *** and returning from the method call. ***
1486 es...............execution state
1487 frame............source frame, receives synchronization slots
1490 *es..............the execution state after popping the stack frame
1492 *******************************************************************************/
1494 u1* replace_pop_activation_record(executionstate_t *es,
1495 sourceframe_t *frame)
1503 stackslot_t *basesp;
1509 /* read the return address */
1511 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1512 if (CODE_IS_LEAFMETHOD(es->code))
1513 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1516 ra = md_stacktrace_get_returnaddress(es->sp,
1517 SIZE_OF_STACKSLOT * es->code->stackframesize);
1519 DOLOG( printf("return address: %p\n", (void*)ra); );
1523 /* calculate the base of the stack frame */
1525 sp = (stackslot_t *) es->sp;
1526 basesp = sp + es->code->stackframesize;
1528 /* read slots used for synchronization */
1530 assert(frame->syncslotcount == 0);
1531 assert(frame->syncslots == NULL);
1532 count = code_get_sync_slot_count(es->code);
1533 frame->syncslotcount = count;
1534 frame->syncslots = DMNEW(replace_val_t, count);
1535 for (i=0; i<count; ++i) {
1536 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1539 /* restore return address, if part of frame */
1541 #if defined(REPLACE_RA_TOP_OF_FRAME)
1542 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1543 if (!CODE_IS_LEAFMETHOD(es->code))
1545 es->intregs[REPLACE_REG_RA] = *--basesp;
1546 #endif /* REPLACE_RA_TOP_OF_FRAME */
1548 #if defined(REPLACE_RA_LINKAGE_AREA)
1549 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1550 if (!CODE_IS_LEAFMETHOD(es->code))
1552 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1553 #endif /* REPLACE_RA_LINKAGE_AREA */
1555 /* restore saved int registers */
1558 for (i=0; i<es->code->savedintcount; ++i) {
1559 while (nregdescint[--reg] != REG_SAV)
1561 es->intregs[reg] = *--basesp;
1564 /* restore saved flt registers */
1568 for (i=0; i<es->code->savedfltcount; ++i) {
1569 while (nregdescfloat[--reg] != REG_SAV)
1571 basesp -= STACK_SLOTS_PER_FLOAT;
1572 es->fltregs[reg] = *(double*)basesp;
1575 #if defined(HAS_ADDRESS_REGISTER_FILE)
1576 /* restore saved adr registers */
1579 for (i=0; i<es->code->savedadrcount; ++i) {
1580 while (nregdescadr[--reg] != REG_SAV)
1582 es->adrregs[reg] = *--basesp;
1586 /* adjust the stackpointer */
1588 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1590 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1591 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1594 /* Set the new pc. Subtract one so we do not hit the replacement point */
1595 /* of the instruction following the call, if there is one. */
1599 /* find the new codeinfo */
1601 pv = md_codegen_get_pv_from_pc(ra);
1603 DOLOG( printf("PV = %p\n", (void*) pv); );
1605 if (pv == NULL) /* XXX can this really happen? */
1608 code = *(codeinfo **)(pv + CodeinfoPointer);
1610 DOLOG( printf("CODE = %p\n", (void*) code); );
1612 /* return NULL if we reached native code */
1617 /* in debugging mode clobber non-saved registers */
1619 #if !defined(NDEBUG)
1621 for (i=0; i<INT_REG_CNT; ++i)
1622 if ((nregdescint[i] != REG_SAV)
1624 && (i != REPLACE_REG_RA)
1627 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1628 for (i=0; i<FLT_REG_CNT; ++i)
1629 if (nregdescfloat[i] != REG_SAV)
1630 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1631 # if defined(HAS_ADDRESS_REGISTER_FILE)
1632 for (i=0; i<ADR_REG_CNT; ++i)
1633 if (nregdescadr[i] != REG_SAV)
1634 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1636 #endif /* !defined(NDEBUG) */
1638 return (code) ? ra : NULL;
1642 /* replace_patch_method_pointer ************************************************
1644 Patch a method pointer (may be in code, data segment, vftbl, or interface
1648 mpp..............address of the method pointer to patch
1649 entrypoint.......the new entrypoint of the method
1650 kind.............kind of call to patch, used only for debugging
1652 *******************************************************************************/
1654 static void replace_patch_method_pointer(methodptr *mpp,
1655 methodptr entrypoint,
1658 #if !defined(NDEBUG)
1663 DOLOG( printf("patch method pointer from: %p to %p\n",
1664 (void*) *mpp, (void*)entrypoint); );
1666 #if !defined(NDEBUG)
1667 oldcode = *(codeinfo **)((u1*)(*mpp) + CodeinfoPointer);
1668 newcode = *(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer);
1670 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1671 method_println(oldcode->m);
1672 printf("\t with %p ", (void*) newcode);
1673 method_println(newcode->m); );
1675 assert(oldcode->m == newcode->m);
1678 /* write the new entrypoint */
1680 *mpp = (methodptr) entrypoint;
1684 /* replace_patch_class *********************************************************
1686 Patch a method in the given class.
1689 vftbl............vftbl of the class
1690 m................the method to patch
1691 oldentrypoint....the old entrypoint to replace
1692 entrypoint.......the new entrypoint
1694 *******************************************************************************/
1696 void replace_patch_class(vftbl_t *vftbl,
1705 /* patch the vftbl of the class */
1707 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1711 /* patch the interface tables */
1713 assert(oldentrypoint);
1715 for (i=0; i < vftbl->interfacetablelength; ++i) {
1716 mpp = vftbl->interfacetable[-i];
1717 mppend = mpp + vftbl->interfacevftbllength[i];
1718 for (; mpp != mppend; ++mpp)
1719 if (*mpp == oldentrypoint) {
1720 replace_patch_method_pointer(mpp, entrypoint, "interface");
1726 /* replace_patch_class_hierarchy ***********************************************
1728 Patch a method in all loaded classes.
1731 m................the method to patch
1732 oldentrypoint....the old entrypoint to replace
1733 entrypoint.......the new entrypoint
1735 *******************************************************************************/
1737 struct replace_patch_data_t {
1743 #define CODEINFO_OF_CODE(entrypoint) \
1744 (*(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer))
1746 #define METHOD_OF_CODE(entrypoint) \
1747 (CODEINFO_OF_CODE(entrypoint)->m)
1749 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1751 vftbl_t *vftbl = c->vftbl;
1754 && vftbl->vftbllength > pd->m->vftblindex
1755 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1756 && METHOD_OF_CODE(vftbl->table[pd->m->vftblindex]) == pd->m)
1758 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1762 void replace_patch_class_hierarchy(methodinfo *m,
1766 struct replace_patch_data_t pd;
1769 pd.oldentrypoint = oldentrypoint;
1770 pd.entrypoint = entrypoint;
1772 DOLOG_SHORT( printf("patching class hierarchy: ");
1773 method_println(m); );
1775 classcache_foreach_loaded_class(
1776 (classcache_foreach_functionptr_t) &replace_patch_callback,
1781 /* replace_patch_future_calls **************************************************
1783 Analyse a call site and depending on the kind of call patch the call, the
1784 virtual function table, or the interface table.
1787 ra...............return address pointing after the call site
1788 callerframe......source frame of the caller
1789 calleeframe......source frame of the callee, must have been mapped
1791 *******************************************************************************/
1793 void replace_patch_future_calls(u1 *ra,
1794 sourceframe_t *callerframe,
1795 sourceframe_t *calleeframe)
1798 methodptr entrypoint;
1799 methodptr oldentrypoint;
1802 codeinfo *calleecode;
1803 methodinfo *calleem;
1808 assert(callerframe->down == calleeframe);
1810 /* get the new codeinfo and the method that shall be entered */
1812 calleecode = calleeframe->tocode;
1815 calleem = calleeframe->method;
1816 assert(calleem == calleecode->m);
1818 entrypoint = (methodptr) calleecode->entrypoint;
1820 /* check if we are at an method entry rplpoint at the innermost frame */
1822 atentry = (calleeframe->down == NULL)
1823 && !(calleem->flags & ACC_STATIC)
1824 && (calleeframe->fromrp->id == 0); /* XXX */
1826 /* get the position to patch, in case it was a statically bound call */
1828 sfi.pv = callerframe->fromcode->entrypoint;
1829 patchpos = md_get_method_patch_address(ra, &sfi, NULL);
1831 if (patchpos == NULL) {
1832 /* the call was dispatched dynamically */
1834 /* we can only patch such calls if we are at the entry point */
1839 assert((calleem->flags & ACC_STATIC) == 0);
1841 oldentrypoint = calleeframe->fromcode->entrypoint;
1843 /* we need to know the instance */
1845 if (!calleeframe->instance.a) {
1846 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1847 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1853 obj = calleeframe->instance.a;
1856 assert(vftbl->class->vftbl == vftbl);
1858 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1860 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1863 /* the call was statically bound */
1865 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1870 /* replace_push_activation_record **********************************************
1872 Push a stack frame onto the execution state.
1874 *** This function imitates the effects of a call and the ***
1875 *** method prolog of the callee. ***
1878 es...............execution state
1879 rpcall...........the replacement point at the call site
1880 callerframe......source frame of the caller, or NULL for creating the
1882 calleeframe......source frame of the callee, must have been mapped
1885 *es..............the execution state after pushing the stack frame
1887 *******************************************************************************/
1889 void replace_push_activation_record(executionstate_t *es,
1891 sourceframe_t *callerframe,
1892 sourceframe_t *calleeframe)
1897 stackslot_t *basesp;
1900 codeinfo *calleecode;
1903 assert(!rpcall || callerframe);
1904 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1905 assert(!rpcall || rpcall == callerframe->torp);
1906 assert(calleeframe);
1907 assert(!callerframe || calleeframe == callerframe->down);
1909 /* the compilation unit we are entering */
1911 calleecode = calleeframe->tocode;
1914 /* calculate the return address */
1917 ra = rpcall->pc + rpcall->callsize;
1919 ra = es->pc + 1 /* XXX this is ugly */;
1921 /* write the return address */
1923 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1924 es->sp -= SIZE_OF_STACKSLOT;
1926 *((stackslot_t *)es->sp) = (stackslot_t) ra;
1927 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1929 #if defined(REPLACE_REG_RA)
1930 es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1933 /* we move into a new code unit */
1935 es->code = calleecode;
1937 /* set the new pc XXX not needed? */
1939 es->pc = calleecode->entrypoint;
1941 /* build the stackframe */
1943 DOLOG( printf("building stackframe of %d words at %p\n",
1944 calleecode->stackframesize, (void*)es->sp); );
1946 sp = (stackslot_t *) es->sp;
1949 sp -= calleecode->stackframesize;
1952 /* in debug mode, invalidate stack frame first */
1954 /* XXX may not invalidate linkage area used by native code! */
1955 #if !defined(NDEBUG) && 0
1956 for (i=0; i<(basesp - sp); ++i) {
1957 sp[i] = 0xdeaddeadU;
1961 /* save the return address register */
1963 #if defined(REPLACE_RA_TOP_OF_FRAME)
1964 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1965 if (!CODE_IS_LEAFMETHOD(calleecode))
1967 *--basesp = (ptrint) ra;
1968 #endif /* REPLACE_RA_TOP_OF_FRAME */
1970 #if defined(REPLACE_RA_LINKAGE_AREA)
1971 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1972 if (!CODE_IS_LEAFMETHOD(calleecode))
1974 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1975 #endif /* REPLACE_RA_LINKAGE_AREA */
1977 /* save int registers */
1980 for (i=0; i<calleecode->savedintcount; ++i) {
1981 while (nregdescint[--reg] != REG_SAV)
1983 *--basesp = es->intregs[reg];
1985 /* XXX may not clobber saved regs used by native code! */
1986 #if !defined(NDEBUG) && 0
1987 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1991 /* save flt registers */
1995 for (i=0; i<calleecode->savedfltcount; ++i) {
1996 while (nregdescfloat[--reg] != REG_SAV)
1998 basesp -= STACK_SLOTS_PER_FLOAT;
1999 *(double*)basesp = es->fltregs[reg];
2001 /* XXX may not clobber saved regs used by native code! */
2002 #if !defined(NDEBUG) && 0
2003 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
2007 #if defined(HAS_ADDRESS_REGISTER_FILE)
2008 /* save adr registers */
2011 for (i=0; i<calleecode->savedadrcount; ++i) {
2012 while (nregdescadr[--reg] != REG_SAV)
2014 *--basesp = es->adrregs[reg];
2016 /* XXX may not clobber saved regs used by native code! */
2017 #if !defined(NDEBUG) && 0
2018 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
2023 /* write slots used for synchronization */
2025 count = code_get_sync_slot_count(calleecode);
2026 assert(count == calleeframe->syncslotcount);
2027 for (i=0; i<count; ++i) {
2028 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2033 es->pv = calleecode->entrypoint;
2035 /* redirect future invocations */
2037 if (callerframe && rpcall) {
2038 #if defined(REPLACE_PATCH_ALL)
2039 if (rpcall->type == callerframe->fromrp->type)
2041 if (rpcall == callerframe->fromrp)
2043 replace_patch_future_calls(ra, callerframe, calleeframe);
2048 /* replace_find_replacement_point **********************************************
2050 Find the replacement point in the given code corresponding to the
2051 position given in the source frame.
2054 code.............the codeinfo in which to search the rplpoint
2055 frame............the source frame defining the position to look for
2056 parent...........parent replacement point to match
2059 the replacement point
2061 *******************************************************************************/
2063 rplpoint * replace_find_replacement_point(codeinfo *code,
2064 sourceframe_t *frame,
2077 DOLOG( printf("searching replacement point for:\n");
2078 replace_source_frame_println(frame); );
2082 DOLOG( printf("code = %p\n", (void*)code); );
2084 rp = code->rplpoints;
2085 i = code->rplpointcount;
2087 if (rp->id == frame->id && rp->method == frame->method
2088 && rp->parent == parent
2089 && replace_normalize_type_map[rp->type] == frame->type)
2091 /* check if returnAddresses match */
2092 /* XXX optimize: only do this if JSRs in method */
2093 DOLOG( printf("checking match for:");
2094 replace_replacement_point_println(rp, 1); fflush(stdout); );
2097 for (j = rp->regalloccount; j--; ++ra) {
2098 if (ra->type == TYPE_RET) {
2099 if (ra->index == RPLALLOC_STACK) {
2100 assert(stacki < frame->javastackdepth);
2101 if (frame->javastack[stacki].i != ra->regoff)
2106 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2107 if (frame->javalocals[ra->index].i != ra->regoff)
2120 #if !defined(NDEBUG)
2121 printf("candidate replacement points were:\n");
2122 rp = code->rplpoints;
2123 i = code->rplpointcount;
2125 replace_replacement_point_println(rp, 1);
2129 vm_abort("no matching replacement point found");
2130 return NULL; /* NOT REACHED */
2134 /* replace_find_replacement_point_for_pc ***************************************
2136 Find the nearest replacement point at or before the given PC.
2139 code.............compilation unit the PC is in
2140 pc...............the machine code PC
2143 the replacement point found, or
2144 NULL if no replacement point was found
2146 *******************************************************************************/
2148 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2154 DOLOG( printf("searching for rp in %p ", (void*)code);
2155 method_println(code->m);
2156 printf("PC = %p\n", (void*)pc); );
2160 rp = code->rplpoints;
2161 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2162 DOLOG( replace_replacement_point_println(rp, 2); );
2167 assert(found == NULL || found->pc + found->callsize >= pc);
2173 /* replace_pop_native_frame ****************************************************
2175 Unroll a native frame in the execution state and create a source frame
2179 es...............current execution state
2180 ss...............the current source state
2181 sfi..............stackframeinfo for the native frame
2184 es...............execution state after unrolling the native frame
2185 ss...............gets the added native source frame
2187 *******************************************************************************/
2189 static void replace_pop_native_frame(executionstate_t *es,
2191 stackframeinfo *sfi)
2193 sourceframe_t *frame;
2199 frame = replace_new_sourceframe(ss);
2203 /* remember pc and size of native frame */
2205 frame->nativepc = es->pc;
2206 frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2207 assert(frame->nativeframesize >= 0);
2209 /* remember values of saved registers */
2212 for (i=0; i<INT_REG_CNT; ++i) {
2213 if (nregdescint[i] == REG_SAV)
2214 frame->nativesavint[j++] = es->intregs[i];
2218 for (i=0; i<FLT_REG_CNT; ++i) {
2219 if (nregdescfloat[i] == REG_SAV)
2220 frame->nativesavflt[j++] = es->fltregs[i];
2223 #if defined(HAS_ADDRESS_REGISTER_FILE)
2225 for (i=0; i<ADR_REG_CNT; ++i) {
2226 if (nregdescadr[i] == REG_SAV)
2227 frame->nativesavadr[j++] = es->adrregs[i];
2231 /* restore saved registers */
2233 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2235 for (i=0; i<INT_REG_CNT; ++i) {
2236 if (nregdescint[i] == REG_SAV)
2237 es->intregs[i] = sfi->intregs[j++];
2240 /* XXX we don't have them, yet, in the sfi, so clear them */
2242 for (i=0; i<INT_REG_CNT; ++i) {
2243 if (nregdescint[i] == REG_SAV)
2248 /* XXX we don't have float registers in the sfi, so clear them */
2250 for (i=0; i<FLT_REG_CNT; ++i) {
2251 if (nregdescfloat[i] == REG_SAV)
2252 es->fltregs[i] = 0.0;
2255 #if defined(HAS_ADDRESS_REGISTER_FILE)
2256 # if defined(ENABLE_GC_CACAO)
2258 for (i=0; i<ADR_REG_CNT; ++i) {
2259 if (nregdescadr[i] == REG_SAV)
2260 es->adrregs[i] = sfi->adrregs[j++];
2263 for (i=0; i<ADR_REG_CNT; ++i) {
2264 if (nregdescadr[i] == REG_SAV)
2270 /* restore pv, pc, and sp */
2272 if (sfi->pv == NULL) {
2273 /* frame of a native function call */
2274 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2279 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2282 /* find the new codeinfo */
2284 DOLOG( printf("PV = %p\n", (void*) es->pv); );
2286 assert(es->pv != NULL);
2288 code = *(codeinfo **)(es->pv + CodeinfoPointer);
2290 DOLOG( printf("CODE = %p\n", (void*) code); );
2296 /* replace_push_native_frame ***************************************************
2298 Rebuild a native frame onto the execution state and remove its source frame.
2300 Note: The native frame is "rebuild" by setting fields like PC and stack
2301 pointer in the execution state accordingly. Values in the
2302 stackframeinfo may be modified, but the actual stack frame of the
2303 native code is not touched.
2306 es...............current execution state
2307 ss...............the current source state
2310 es...............execution state after re-rolling the native frame
2311 ss...............the native source frame is removed
2313 *******************************************************************************/
2315 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2317 sourceframe_t *frame;
2323 DOLOG( printf("pushing native frame\n"); );
2325 /* remove the frame from the source state */
2329 assert(REPLACE_IS_NATIVE_FRAME(frame));
2331 ss->frames = frame->down;
2333 /* assert that the native frame has not moved */
2335 assert(es->sp == frame->sfi->sp);
2337 /* update saved registers in the stackframeinfo */
2339 #if defined(ENABLE_GC_CACAO)
2341 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2342 for (i=0; i<INT_REG_CNT; ++i) {
2343 if (nregdescint[i] == REG_SAV)
2344 frame->sfi->intregs[j++] = es->intregs[i];
2347 for (i=0; i<ADR_REG_CNT; ++i) {
2348 if (nregdescadr[i] == REG_SAV)
2349 frame->sfi->adrregs[j++] = es->adrregs[i];
2353 /* XXX leave float registers untouched here */
2356 /* restore saved registers */
2359 for (i=0; i<INT_REG_CNT; ++i) {
2360 if (nregdescint[i] == REG_SAV)
2361 es->intregs[i] = frame->nativesavint[j++];
2365 for (i=0; i<FLT_REG_CNT; ++i) {
2366 if (nregdescfloat[i] == REG_SAV)
2367 es->fltregs[i] = frame->nativesavflt[j++];
2370 #if defined(HAS_ADDRESS_REGISTER_FILE)
2372 for (i=0; i<ADR_REG_CNT; ++i) {
2373 if (nregdescadr[i] == REG_SAV)
2374 es->adrregs[i] = frame->nativesavadr[j++];
2378 /* skip the native frame on the machine stack */
2380 es->sp -= frame->nativeframesize;
2382 /* set the pc the next frame must return to */
2384 es->pc = frame->nativepc;
2388 /* replace_recover_source_state ************************************************
2390 Recover the source state from the given replacement point and execution
2394 rp...............replacement point that has been reached, if any
2395 sfi..............stackframeinfo, if called from native code
2396 es...............execution state at the replacement point rp
2401 *******************************************************************************/
2403 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2404 stackframeinfo *sfi,
2405 executionstate_t *es)
2410 #if defined(REPLACE_STATISTICS)
2414 /* create the source frame structure in dump memory */
2416 ss = DNEW(sourcestate_t);
2419 /* each iteration of the loop recovers one source frame */
2426 DOLOG( replace_executionstate_println(es); );
2428 /* if we are not at a replacement point, it is a native frame */
2431 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2434 replace_pop_native_frame(es, ss, sfi);
2437 if (es->code == NULL)
2440 goto after_machine_frame;
2443 /* read the values for this source frame from the execution state */
2445 DOLOG( printf("recovering source state for%s:\n",
2446 (ss->frames == NULL) ? " TOPFRAME" : "");
2447 replace_replacement_point_println(rp, 1); );
2449 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2451 #if defined(ENABLE_VMLOG)
2452 vmlog_cacao_unrol_method(ss->frames->method);
2455 #if defined(REPLACE_STATISTICS)
2456 REPLACE_COUNT(stat_frames);
2458 replace_statistics_source_frame(ss->frames);
2461 /* in locked areas (below native frames), identity map the frame */
2464 ss->frames->torp = ss->frames->fromrp;
2465 ss->frames->tocode = ss->frames->fromcode;
2468 /* unroll to the next (outer) frame */
2471 /* this frame is in inlined code */
2473 DOLOG( printf("INLINED!\n"); );
2477 assert(rp->type == RPLPOINT_TYPE_INLINE);
2478 REPLACE_COUNT(stat_unroll_inline);
2481 /* this frame had been called at machine-level. pop it. */
2483 DOLOG( printf("UNWIND\n"); );
2485 ra = replace_pop_activation_record(es, ss->frames);
2487 DOLOG( printf("REACHED NATIVE CODE\n"); );
2491 #if !defined(ENABLE_GC_CACAO)
2492 break; /* XXX remove to activate native frames */
2497 /* find the replacement point at the call site */
2499 after_machine_frame:
2500 rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2503 vm_abort("could not find replacement point while unrolling call");
2505 DOLOG( printf("found replacement point.\n");
2506 replace_replacement_point_println(rp, 1); );
2508 assert(rp->type == RPLPOINT_TYPE_CALL);
2509 REPLACE_COUNT(stat_unroll_call);
2511 } /* end loop over source frames */
2513 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2519 /* replace_map_source_state ****************************************************
2521 Map each source frame in the given source state to a target replacement
2522 point and compilation unit. If no valid code is available for a source
2523 frame, it is (re)compiled.
2526 ss...............the source state
2529 ss...............the source state, modified: The `torp` and `tocode`
2530 fields of each source frame are set.
2533 true.............everything went ok
2534 false............an exception has been thrown
2536 *******************************************************************************/
2538 static bool replace_map_source_state(sourcestate_t *ss)
2540 sourceframe_t *frame;
2543 rplpoint *parent; /* parent of inlined rplpoint */
2544 #if defined(REPLACE_STATISTICS)
2551 /* iterate over the source frames from outermost to innermost */
2553 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2555 /* XXX skip native frames */
2557 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2562 /* map frames which are not already mapped */
2564 if (frame->tocode) {
2565 code = frame->tocode;
2570 assert(frame->torp == NULL);
2572 if (parent == NULL) {
2573 /* find code for this frame */
2575 #if defined(REPLACE_STATISTICS)
2576 oldcode = frame->method->code;
2578 /* request optimization of hot methods and their callers */
2580 if (frame->method->hitcountdown < 0
2581 || (frame->down && frame->down->method->hitcountdown < 0))
2582 jit_request_optimization(frame->method);
2584 code = jit_get_current_code(frame->method);
2587 return false; /* exception */
2589 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2594 /* map this frame */
2596 rp = replace_find_replacement_point(code, frame, parent);
2598 frame->tocode = code;
2602 if (rp->type == RPLPOINT_TYPE_CALL) {
2615 /* replace_map_source_state_identity *******************************************
2617 Map each source frame in the given source state to the same replacement
2618 point and compilation unit it was derived from. This is mainly used for
2622 ss...............the source state
2625 ss...............the source state, modified: The `torp` and `tocode`
2626 fields of each source frame are set.
2628 *******************************************************************************/
2630 #if defined(ENABLE_GC_CACAO)
2631 static void replace_map_source_state_identity(sourcestate_t *ss)
2633 sourceframe_t *frame;
2635 /* iterate over the source frames from outermost to innermost */
2637 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2639 /* skip native frames */
2641 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2645 /* map frames using the identity mapping */
2647 if (frame->tocode) {
2648 assert(frame->tocode == frame->fromcode);
2649 assert(frame->torp == frame->fromrp);
2651 assert(frame->tocode == NULL);
2652 assert(frame->torp == NULL);
2653 frame->tocode = frame->fromcode;
2654 frame->torp = frame->fromrp;
2661 /* replace_build_execution_state_intern ****************************************
2663 Build an execution state for the given (mapped) source state.
2665 !!! CAUTION: This function rewrites the machine stack !!!
2667 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2670 ss...............the source state. Must have been mapped by
2671 replace_map_source_state before.
2672 es...............the base execution state on which to build
2675 *es..............the new execution state
2677 *******************************************************************************/
2679 void replace_build_execution_state_intern(sourcestate_t *ss,
2680 executionstate_t *es)
2683 sourceframe_t *prevframe;
2690 while (ss->frames) {
2692 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2693 prevframe = ss->frames;
2694 replace_push_native_frame(es, ss);
2700 if (parent == NULL) {
2701 /* create a machine-level stack frame */
2703 DOLOG( printf("pushing activation record for:\n");
2704 if (rp) replace_replacement_point_println(rp, 1);
2705 else printf("\tfirst frame\n"); );
2707 replace_push_activation_record(es, rp, prevframe, ss->frames);
2709 DOLOG( replace_executionstate_println(es); );
2712 rp = ss->frames->torp;
2715 DOLOG( printf("creating execution state for%s:\n",
2716 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2717 replace_replacement_point_println(ss->frames->fromrp, 1);
2718 replace_replacement_point_println(rp, 1); );
2720 es->code = ss->frames->tocode;
2721 prevframe = ss->frames;
2723 #if defined(ENABLE_VMLOG)
2724 vmlog_cacao_rerol_method(ss->frames->method);
2727 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2729 DOLOG( replace_executionstate_println(es); );
2731 if (rp->type == RPLPOINT_TYPE_CALL) {
2742 /* replace_build_execution_state ***********************************************
2744 This function contains the final phase of replacement. It builds the new
2745 execution state, releases dump memory, and returns to the calling
2746 assembler function which finishes replacement.
2748 NOTE: This function is called from asm_replacement_in, with the stack
2749 pointer at the start of the safe stack area.
2751 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2753 CAUTION: This function and its children must not use a lot of stack!
2754 There are only REPLACE_SAFESTACK_SIZE bytes of C stack
2758 st...............the safestack contained the necessary data
2760 *******************************************************************************/
2762 void replace_build_execution_state(replace_safestack_t *st)
2764 replace_build_execution_state_intern(st->ss, &(st->es));
2766 DOLOG( replace_executionstate_println(&(st->es)); );
2768 /* release dump area */
2770 dump_release(st->dumpsize);
2772 /* new code is entered after returning */
2774 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2778 /* replace_alloc_safestack *****************************************************
2780 Allocate a safe stack area to use during the final phase of replacement.
2781 The returned area is not initialized. This must be done by the caller.
2784 a newly allocated replace_safestack_t *
2786 *******************************************************************************/
2788 static replace_safestack_t *replace_alloc_safestack()
2791 replace_safestack_t *st;
2793 mem = MNEW(u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2795 st = (replace_safestack_t *) ((ptrint)(mem + REPLACE_STACK_ALIGNMENT - 1)
2796 & ~(REPLACE_STACK_ALIGNMENT - 1));
2798 #if !defined(NDEBUG)
2799 memset(st, 0xa5, sizeof(replace_safestack_t));
2808 /* replace_free_safestack ******************************************************
2810 Free the given safestack structure, making a copy of the contained
2811 execution state before freeing it.
2813 NOTE: This function is called from asm_replacement_in.
2816 st...............the safestack to free
2817 tmpes............where to copy the execution state to
2820 *tmpes...........receives a copy of st->es
2822 *******************************************************************************/
2824 void replace_free_safestack(replace_safestack_t *st, executionstate_t *tmpes)
2828 /* copy the executionstate_t to the temporary location */
2832 /* get the memory address to free */
2836 /* destroy memory (in debug mode) */
2838 #if !defined(NDEBUG)
2839 memset(st, 0xa5, sizeof(replace_safestack_t));
2842 /* free the safe stack struct */
2844 MFREE(mem, u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2848 /* replace_me_wrapper **********************************************************
2852 *******************************************************************************/
2854 bool replace_me_wrapper(u1 *pc)
2858 executionstate_t es;
2860 /* search the codeinfo for the given PC */
2862 code = code_find_codeinfo_for_pc(pc);
2865 /* search for a replacement point at the given PC */
2868 rp = replace_find_replacement_point_for_pc(code, pc);
2869 assert(rp == NULL || rp->pc == pc);
2875 for (i=0,rp2=code->rplpoints; i<code->rplpointcount; i++,rp2++) {
2882 /* check if the replacement point is active */
2884 if (rp != NULL && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
2886 /*md_replace_executionstate_read(&es, context);*/
2888 replace_me(rp, &es);
2897 /* replace_me ******************************************************************
2899 This function is called by asm_replacement_out when a thread reaches
2900 a replacement point. `replace_me` must map the execution state to the
2901 target replacement point and let execution continue there.
2903 This function never returns!
2906 rp...............replacement point that has been reached
2907 es...............execution state read by asm_replacement_out
2909 *******************************************************************************/
2911 void replace_me(rplpoint *rp, executionstate_t *es)
2913 stackframeinfo *sfi;
2915 sourceframe_t *frame;
2918 replace_safestack_t *safestack;
2919 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2920 threadobject *thread;
2924 es->code = code_find_codeinfo_for_pc(rp->pc);
2926 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2927 stat_replacements, (void*)THREADOBJECT,
2929 method_println(es->code->m); );
2931 DOLOG( replace_replacement_point_println(rp, 1);
2932 replace_executionstate_println(es); );
2934 REPLACE_COUNT(stat_replacements);
2936 /* mark start of dump memory area */
2938 dumpsize = dump_size();
2940 /* get the stackframeinfo for the current thread */
2942 sfi = STACKFRAMEINFO;
2944 /* recover source state */
2946 ss = replace_recover_source_state(rp, sfi, es);
2948 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2949 /* if there is a collection pending, we assume the replacement point should
2950 suspend this thread */
2954 thread = THREADOBJECT;
2956 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2958 /* map the sourcestate using the identity mapping */
2959 replace_map_source_state_identity(ss);
2961 /* since we enter the same method again, we turn off rps now */
2962 /* XXX michi: can we really do this? what if the rp was active before
2963 we activated it for the gc? */
2966 frame = frame->down;
2967 replace_deactivate_replacement_points(frame->tocode);
2969 /* remember executionstate and sourcestate for this thread */
2970 GC_EXECUTIONSTATE = es;
2971 GC_SOURCESTATE = ss;
2973 /* really suspend this thread now (PC = 0) */
2974 threads_suspend_ack(NULL, NULL);
2976 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2979 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2981 /* map the source state */
2983 if (!replace_map_source_state(ss))
2984 vm_abort("exception during method replacement");
2986 DOLOG( replace_sourcestate_println(ss); );
2988 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2990 /* avoid infinite loops by self-replacement */
2994 frame = frame->down;
2996 if (frame->torp == origrp) {
2998 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
3000 replace_deactivate_replacement_points(frame->tocode);
3003 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
3007 /* write execution state of new code */
3009 DOLOG( replace_executionstate_println(es); );
3011 /* allocate a safe stack area and copy all needed data there */
3013 safestack = replace_alloc_safestack();
3015 safestack->es = *es;
3017 safestack->dumpsize = dumpsize;
3019 /* call the assembler code for the last phase of replacement */
3021 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
3022 /*asm_replacement_in(&(safestack->es), safestack);*/
3025 abort(); /* NOT REACHED */
3029 /******************************************************************************/
3030 /* NOTE: Stuff specific to the exact GC is below. */
3031 /******************************************************************************/
3033 #if defined(ENABLE_GC_CACAO)
3034 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
3036 stackframeinfo *sfi;
3037 executionstate_t *es;
3040 /* get the stackframeinfo of this thread */
3041 assert(thread == THREADOBJECT);
3042 sfi = STACKFRAMEINFO;
3044 /* create the execution state */
3045 es = DNEW(executionstate_t);
3048 es->pv = 0; /* since we are in a native, PV is invalid! */
3049 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
3051 /* we assume we are in a native (no replacement point)! */
3052 ss = replace_recover_source_state(NULL, sfi, es);
3054 /* map the sourcestate using the identity mapping */
3055 replace_map_source_state_identity(ss);
3057 /* remember executionstate and sourcestate for this thread */
3058 GC_EXECUTIONSTATE = es;
3059 GC_SOURCESTATE = ss;
3064 /******************************************************************************/
3065 /* NOTE: No important code below. */
3066 /******************************************************************************/
3069 /* statistics *****************************************************************/
3071 #if defined(REPLACE_STATISTICS)
3072 static void print_freq(FILE *file,int *array,int limit)
3077 for (i=0; i<limit; ++i)
3079 sum += array[limit];
3080 for (i=0; i<limit; ++i) {
3082 fprintf(file," %3d: %8d (cum %3d%%)\n",
3083 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3085 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3087 #endif /* defined(REPLACE_STATISTICS) */
3090 #if defined(REPLACE_STATISTICS)
3092 #define REPLACE_PRINT_DIST(name, array) \
3093 printf(" " name " distribution:\n"); \
3094 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3096 void replace_print_statistics(void)
3098 printf("replacement statistics:\n");
3099 printf(" # of replacements: %d\n", stat_replacements);
3100 printf(" # of frames: %d\n", stat_frames);
3101 printf(" # of recompilations: %d\n", stat_recompile);
3102 printf(" patched static calls:%d\n", stat_staticpatch);
3103 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3104 printf(" unrolled calls: %d\n", stat_unroll_call);
3105 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3106 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3107 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3108 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3109 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3110 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3111 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3112 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3113 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3114 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3116 printf(" # of methods: %d\n", stat_methods);
3117 printf(" # of replacement points: %d\n", stat_rploints);
3118 printf(" # of regallocs: %d\n", stat_regallocs);
3119 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3120 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3121 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3125 #endif /* defined(REPLACE_STATISTICS) */
3128 #if defined(REPLACE_STATISTICS)
3129 static void replace_statistics_source_frame(sourceframe_t *frame)
3138 for (i=0; i<frame->javalocalcount; ++i) {
3139 switch (frame->javalocaltype[i]) {
3140 case TYPE_ADR: adr++; break;
3141 case TYPE_RET: ret++; break;
3142 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3143 case TYPE_VOID: vd++; break;
3148 REPLACE_COUNT_DIST(stat_dist_locals, n);
3149 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3150 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3151 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3152 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3153 adr = ret = prim = n = 0;
3154 for (i=0; i<frame->javastackdepth; ++i) {
3155 switch (frame->javastacktype[i]) {
3156 case TYPE_ADR: adr++; break;
3157 case TYPE_RET: ret++; break;
3158 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3162 REPLACE_COUNT_DIST(stat_dist_stack, n);
3163 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3164 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3165 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3167 #endif /* defined(REPLACE_STATISTICS) */
3170 /* debugging helpers **********************************************************/
3172 /* replace_replacement_point_println *******************************************
3174 Print replacement point info.
3177 rp...............the replacement point to print
3179 *******************************************************************************/
3181 #if !defined(NDEBUG)
3183 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3185 static char *replace_type_str[] = {
3195 void replace_replacement_point_println(rplpoint *rp, int depth)
3201 printf("(rplpoint *)NULL\n");
3205 for (j=0; j<depth; ++j)
3208 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3209 rp->id, (void*)rp,rp->pc,rp->callsize,
3210 replace_type_str[rp->type]);
3211 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3213 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3214 printf(" COUNTDOWN");
3215 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3217 printf(" parent:%p\n", (void*)rp->parent);
3218 for (j=0; j<depth; ++j)
3220 printf("ra:%d = [", rp->regalloccount);
3222 for (j=0; j<rp->regalloccount; ++j) {
3225 index = rp->regalloc[j].index;
3227 case RPLALLOC_STACK: printf("S"); break;
3228 case RPLALLOC_PARAM: printf("P"); break;
3229 case RPLALLOC_SYNC : printf("Y"); break;
3230 default: printf("%d", index);
3232 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3233 if (rp->regalloc[j].type == TYPE_RET) {
3234 printf("ret(L%03d)", rp->regalloc[j].regoff);
3237 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3242 for (j=0; j<depth; ++j)
3245 method_print(rp->method);
3249 #endif /* !defined(NDEBUG) */
3252 /* replace_show_replacement_points *********************************************
3254 Print replacement point info.
3257 code.............codeinfo whose replacement points should be printed.
3259 *******************************************************************************/
3261 #if !defined(NDEBUG)
3262 void replace_show_replacement_points(codeinfo *code)
3270 printf("(codeinfo *)NULL\n");
3274 printf("\treplacement points: %d\n",code->rplpointcount);
3276 printf("\ttotal allocations : %d\n",code->regalloccount);
3277 printf("\tsaved int regs : %d\n",code->savedintcount);
3278 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3279 #if defined(HAS_ADDRESS_REGISTER_FILE)
3280 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3282 printf("\tmemuse : %d\n",code->memuse);
3286 for (i=0; i<code->rplpointcount; ++i) {
3287 rp = code->rplpoints + i;
3290 parent = rp->parent;
3293 parent = parent->parent;
3295 replace_replacement_point_println(rp, depth);
3301 /* replace_executionstate_println **********************************************
3303 Print execution state
3306 es...............the execution state to print
3308 *******************************************************************************/
3310 #if !defined(NDEBUG)
3311 void replace_executionstate_println(executionstate_t *es)
3319 printf("(executionstate_t *)NULL\n");
3323 printf("executionstate_t:\n");
3324 printf("\tpc = %p",(void*)es->pc);
3325 printf(" sp = %p",(void*)es->sp);
3326 printf(" pv = %p\n",(void*)es->pv);
3327 #if defined(ENABLE_DISASSEMBLER)
3328 for (i=0; i<INT_REG_CNT; ++i) {
3333 #if SIZEOF_VOID_P == 8
3334 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3336 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3341 for (i=0; i<FLT_REG_CNT; ++i) {
3346 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3350 # if defined(HAS_ADDRESS_REGISTER_FILE)
3351 for (i=0; i<ADR_REG_CNT; ++i) {
3356 printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
3363 sp = (stackslot_t *) es->sp;
3368 methoddesc *md = es->code->m->parseddesc;
3369 slots = es->code->stackframesize;
3370 extraslots = 1 + md->memuse;
3377 printf("\tstack slots(+%d) at sp:", extraslots);
3378 for (i=0; i<slots+extraslots; ++i) {
3381 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3382 #ifdef HAS_4BYTE_STACKSLOT
3383 printf("%08lx",(unsigned long)*sp++);
3385 printf("%016llx",(unsigned long long)*sp++);
3387 printf("%c", (i >= slots) ? ')' : ' ');
3392 printf("\tcode: %p", (void*)es->code);
3393 if (es->code != NULL) {
3394 printf(" stackframesize=%d ", es->code->stackframesize);
3395 method_print(es->code->m);
3403 #if !defined(NDEBUG)
3404 static void java_value_print(s4 type, replace_val_t value)
3409 printf("%016llx",(unsigned long long) value.l);
3411 if (type < 0 || type > TYPE_RET)
3412 printf(" <INVALID TYPE:%d>", type);
3414 printf(" %s", show_jit_type_names[type]);
3416 if (type == TYPE_ADR && value.a != NULL) {
3419 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3421 if (obj->vftbl->class == class_java_lang_String) {
3423 u = javastring_toutf(obj, false);
3424 utf_display_printable_ascii(u);
3428 else if (type == TYPE_INT) {
3429 printf(" %ld", (long) value.i);
3431 else if (type == TYPE_LNG) {
3432 printf(" %lld", (long long) value.l);
3434 else if (type == TYPE_FLT) {
3435 printf(" %f", value.f);
3437 else if (type == TYPE_DBL) {
3438 printf(" %f", value.d);
3441 #endif /* !defined(NDEBUG) */
3444 #if !defined(NDEBUG)
3445 void replace_source_frame_println(sourceframe_t *frame)
3450 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3451 printf("\tNATIVE\n");
3452 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3453 printf("\tnativepc: %p\n", frame->nativepc);
3454 printf("\tframesize: %d\n", frame->nativeframesize);
3457 for (i=0; i<INT_REG_CNT; ++i) {
3458 if (nregdescint[i] == REG_SAV)
3459 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3463 for (i=0; i<FLT_REG_CNT; ++i) {
3464 if (nregdescfloat[i] == REG_SAV)
3465 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3473 method_println(frame->method);
3474 printf("\tid: %d\n", frame->id);
3475 printf("\ttype: %s\n", replace_type_str[frame->type]);
3478 if (frame->instance.a) {
3479 printf("\tinstance: ");
3480 java_value_print(TYPE_ADR, frame->instance);
3484 if (frame->javalocalcount) {
3485 printf("\tlocals (%d):\n",frame->javalocalcount);
3486 for (i=0; i<frame->javalocalcount; ++i) {
3487 t = frame->javalocaltype[i];
3488 if (t == TYPE_VOID) {
3489 printf("\tlocal[ %2d] = void\n",i);
3492 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3493 java_value_print(t, frame->javalocals[i]);
3500 if (frame->javastackdepth) {
3501 printf("\tstack (depth %d):\n",frame->javastackdepth);
3502 for (i=0; i<frame->javastackdepth; ++i) {
3503 t = frame->javastacktype[i];
3504 if (t == TYPE_VOID) {
3505 printf("\tstack[%2d] = void", i);
3508 printf("\tstack[%2d] = ",i);
3509 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3516 if (frame->syncslotcount) {
3517 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3518 for (i=0; i<frame->syncslotcount; ++i) {
3519 printf("\tslot[%2d] = ",i);
3520 #ifdef HAS_4BYTE_STACKSLOT
3521 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3523 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3529 if (frame->fromcode) {
3530 printf("\tfrom %p ", (void*)frame->fromcode);
3531 method_println(frame->fromcode->m);
3533 if (frame->tocode) {
3534 printf("\tto %p ", (void*)frame->tocode);
3535 method_println(frame->tocode->m);
3538 if (frame->fromrp) {
3539 printf("\tfrom replacement point:\n");
3540 replace_replacement_point_println(frame->fromrp, 2);
3543 printf("\tto replacement point:\n");
3544 replace_replacement_point_println(frame->torp, 2);
3549 #endif /* !defined(NDEBUG) */
3552 /* replace_sourcestate_println *************************************************
3557 ss...............the source state to print
3559 *******************************************************************************/
3561 #if !defined(NDEBUG)
3562 void replace_sourcestate_println(sourcestate_t *ss)
3565 sourceframe_t *frame;
3568 printf("(sourcestate_t *)NULL\n");
3572 printf("sourcestate_t:\n");
3574 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3575 printf(" frame %d:\n", i);
3576 replace_source_frame_println(frame);
3582 /* replace_sourcestate_println_short *******************************************
3584 Print a compact representation of the given source state.
3587 ss...............the source state to print
3589 *******************************************************************************/
3591 #if !defined(NDEBUG)
3592 void replace_sourcestate_println_short(sourcestate_t *ss)
3594 sourceframe_t *frame;
3596 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3599 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3600 printf("NATIVE (pc %p size %d) ",
3601 (void*)frame->nativepc, frame->nativeframesize);
3602 replace_stackframeinfo_println(frame->sfi);
3607 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3610 printf("%s", replace_type_str[frame->fromrp->type]);
3612 if (frame->torp && frame->torp->type != frame->fromrp->type)
3613 printf("->%s", replace_type_str[frame->torp->type]);
3615 if (frame->tocode != frame->fromcode)
3616 printf(" (%p->%p/%d) ",
3617 (void*) frame->fromcode, (void*) frame->tocode,
3620 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3622 method_println(frame->method);
3627 #if !defined(NDEBUG)
3628 static void replace_stackframeinfo_println(stackframeinfo *sfi)
3630 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3631 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3632 (void*)sfi->ra, (void*)sfi->xpc);
3635 method_println(sfi->method);
3642 * These are local overrides for various environment variables in Emacs.
3643 * Please do not remove this and leave it at the end of the file, where
3644 * Emacs will automagically detect them.
3645 * ---------------------------------------------------------------------
3648 * indent-tabs-mode: t
3652 * vim:noexpandtab:sw=4:ts=4: