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
35 #if defined(ENABLE_GC_CACAO)
36 # include "mm/cacao-gc/gc.h"
39 #include "mm/memory.h"
41 #include "threads/threads-common.h"
43 #include "toolbox/logging.h"
45 #include "vm/stringlocal.h"
47 #include "vm/jit/abi.h"
48 #include "vm/jit/asmpart.h"
49 #include "vm/jit/disass.h"
50 #include "vm/jit/jit.h"
51 #include "vm/jit/md.h"
52 #include "vm/jit/methodheader.h"
53 #include "vm/jit/replace.h"
54 #include "vm/jit/show.h"
55 #include "vm/jit/stack.h"
57 #include "vmcore/options.h"
58 #include "vmcore/classcache.h"
61 #define REPLACE_PATCH_DYNAMIC_CALL
62 /*#define REPLACE_PATCH_ALL*/
64 #if defined(ENABLE_VMLOG)
65 #include <vmlog_cacao.h>
68 /*** architecture-dependent configuration *************************************/
70 /* first unset the macros (default) */
71 #undef REPLACE_RA_BETWEEN_FRAMES
72 #undef REPLACE_RA_TOP_OF_FRAME
73 #undef REPLACE_RA_LINKAGE_AREA
74 #undef REPLACE_LEAFMETHODS_RA_REGISTER
77 /* i386, x86_64 and m68k */
78 #if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
79 #define REPLACE_RA_BETWEEN_FRAMES
81 #elif defined(__ALPHA__)
82 #define REPLACE_RA_TOP_OF_FRAME
83 #define REPLACE_LEAFMETHODS_RA_REGISTER
84 #define REPLACE_REG_RA REG_RA
86 #elif defined(__POWERPC__)
87 #define REPLACE_RA_LINKAGE_AREA
88 #define REPLACE_LEAFMETHODS_RA_REGISTER
89 #define REPLACE_REG_RA REG_ITMP3 /* the execution state has the LR in itmp3 */
91 #elif defined(__S390__)
92 #define REPLACE_RA_TOP_OF_FRAME
93 #define REPLACE_REG_RA REG_ITMP3
97 /*** configuration of native stack slot size **********************************/
99 /* XXX this should be in md-abi.h files, probably */
101 #if defined(HAS_4BYTE_STACKSLOT)
102 #define SIZE_OF_STACKSLOT 4
103 #define STACK_SLOTS_PER_FLOAT 2
104 typedef u4 stackslot_t;
106 #define SIZE_OF_STACKSLOT 8
107 #define STACK_SLOTS_PER_FLOAT 1
108 typedef u8 stackslot_t;
112 /*** debugging ****************************************************************/
115 static void java_value_print(s4 type, replace_val_t value);
116 static void replace_stackframeinfo_println(stackframeinfo *sfi);
120 #define DOLOG(code) do{ if (opt_TraceReplacement > 1) { code; } } while(0)
121 #define DOLOG_SHORT(code) do{ if (opt_TraceReplacement > 0) { code; } } while(0)
124 #define DOLOG_SHORT(code)
128 /*** statistics ***************************************************************/
130 #define REPLACE_STATISTICS
132 #if defined(REPLACE_STATISTICS)
134 static int stat_replacements = 0;
135 static int stat_frames = 0;
136 static int stat_recompile = 0;
137 static int stat_staticpatch = 0;
138 static int stat_unroll_inline = 0;
139 static int stat_unroll_call = 0;
140 static int stat_dist_frames[20] = { 0 };
141 static int stat_dist_locals[20] = { 0 };
142 static int stat_dist_locals_adr[10] = { 0 };
143 static int stat_dist_locals_prim[10] = { 0 };
144 static int stat_dist_locals_ret[10] = { 0 };
145 static int stat_dist_locals_void[10] = { 0 };
146 static int stat_dist_stack[10] = { 0 };
147 static int stat_dist_stack_adr[10] = { 0 };
148 static int stat_dist_stack_prim[10] = { 0 };
149 static int stat_dist_stack_ret[10] = { 0 };
150 static int stat_methods = 0;
151 static int stat_rploints = 0;
152 static int stat_regallocs = 0;
153 static int stat_dist_method_rplpoints[20] = { 0 };
155 #define REPLACE_COUNT(cnt) (cnt)++
156 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
157 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
159 #define REPLACE_COUNT_DIST(array, val) \
161 int limit = (sizeof(array) / sizeof(int)) - 1; \
162 if ((val) < (limit)) (array)[val]++; \
163 else (array)[limit]++; \
166 static void replace_statistics_source_frame(sourceframe_t *frame);
170 #define REPLACE_COUNT(cnt)
171 #define REPLACE_COUNT_IF(cnt, cond)
172 #define REPLACE_COUNT_INC(cnt, inc)
173 #define REPLACE_COUNT_DIST(array, val)
175 #endif /* defined(REPLACE_STATISTICS) */
178 /*** constants used internally ************************************************/
180 #define TOP_IS_NORMAL 0
181 #define TOP_IS_ON_STACK 1
182 #define TOP_IS_IN_ITMP1 2
183 #define TOP_IS_VOID 3
186 /******************************************************************************/
187 /* PART I: Creating / freeing replacement points */
188 /******************************************************************************/
191 /* replace_create_replacement_point ********************************************
193 Create a replacement point.
196 jd...............current jitdata
197 iinfo............inlining info for the current position
198 rp...............pre-allocated (uninitialized) rplpoint
199 type.............RPLPOINT_TYPE constant
200 iptr.............current instruction
201 *pra.............current rplalloc pointer
202 javalocals.......the javalocals at the current point
203 stackvars........the stack variables at the current point
204 stackdepth.......the stack depth at the current point
205 paramcount.......number of parameters at the start of stackvars
208 *rpa.............points to the next free rplalloc
210 *******************************************************************************/
212 static void replace_create_replacement_point(jitdata *jd,
213 insinfo_inline *iinfo,
230 REPLACE_COUNT(stat_rploints);
232 rp->method = (iinfo) ? iinfo->method : jd->m;
233 rp->pc = NULL; /* set by codegen */
234 rp->callsize = 0; /* set by codegen */
238 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
240 /* XXX unify these two fields */
241 rp->parent = (iinfo) ? iinfo->rp : NULL;
243 /* store local allocation info of javalocals */
246 for (i = 0; i < rp->method->maxlocals; ++i) {
247 index = javalocals[i];
254 ra->flags = v->flags & (INMEMORY);
255 ra->regoff = v->vv.regoff;
259 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
267 /* store allocation info of java stack vars */
269 for (i = 0; i < stackdepth; ++i) {
270 v = VAR(stackvars[i]);
271 ra->flags = v->flags & (INMEMORY);
272 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
274 /* XXX how to handle locals on the stack containing returnAddresses? */
275 if (v->type == TYPE_RET) {
276 assert(stackvars[i] >= jd->localcount);
277 ra->regoff = v->vv.retaddr->nr;
280 ra->regoff = v->vv.regoff;
284 /* total number of allocations */
286 rp->regalloccount = ra - rp->regalloc;
292 /* replace_create_inline_start_replacement_point *******************************
294 Create an INLINE_START replacement point.
297 jd...............current jitdata
298 rp...............pre-allocated (uninitialized) rplpoint
299 iptr.............current instruction
300 *pra.............current rplalloc pointer
301 javalocals.......the javalocals at the current point
304 *rpa.............points to the next free rplalloc
307 the insinfo_inline * for the following inlined body
309 *******************************************************************************/
311 static insinfo_inline * replace_create_inline_start_replacement_point(
318 insinfo_inline *calleeinfo;
321 calleeinfo = iptr->sx.s23.s3.inlineinfo;
325 replace_create_replacement_point(jd, calleeinfo->parent, rp,
326 RPLPOINT_TYPE_INLINE, iptr, pra,
328 calleeinfo->stackvars, calleeinfo->stackvarscount,
329 calleeinfo->paramcount);
331 if (calleeinfo->synclocal != UNUSED) {
333 ra->index = RPLALLOC_SYNC;
334 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
335 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
345 /* replace_create_replacement_points *******************************************
347 Create the replacement points for the given code.
350 jd...............current jitdata, must not have any replacement points
353 code->rplpoints.......set to the list of replacement points
354 code->rplpointcount...number of replacement points
355 code->regalloc........list of allocation info
356 code->regalloccount...total length of allocation info list
357 code->globalcount.....number of global allocations at the
358 start of code->regalloc
361 true.............everything ok
362 false............an exception has been thrown
364 *******************************************************************************/
366 #define CLEAR_javalocals(array, method) \
368 for (i=0; i<(method)->maxlocals; ++i) \
369 (array)[i] = UNUSED; \
372 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
374 if ((array) != NULL) \
375 MCOPY((dest), (array), s4, (method)->maxlocals); \
377 CLEAR_javalocals((dest), (method)); \
380 #define COUNT_javalocals(array, method, counter) \
382 for (i=0; i<(method)->maxlocals; ++i) \
383 if ((array)[i] != UNUSED) \
387 bool replace_create_replacement_points(jitdata *jd)
405 insinfo_inline *iinfo;
408 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
412 REPLACE_COUNT(stat_methods);
414 /* get required compiler data */
419 /* assert that we wont overwrite already allocated data */
423 assert(code->rplpoints == NULL);
424 assert(code->rplpointcount == 0);
425 assert(code->regalloc == NULL);
426 assert(code->regalloccount == 0);
427 assert(code->globalcount == 0);
431 /* set codeinfo flags */
433 if (jd->isleafmethod)
434 CODE_SETFLAG_LEAFMETHOD(code);
436 /* in instance methods, we may need a rplpoint at the method entry */
438 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
439 if (!(m->flags & ACC_STATIC)) {
440 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
446 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
448 /* iterate over the basic block list to find replacement points */
453 javalocals = DMNEW(s4, jd->maxlocals);
455 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
459 if (bptr->flags < BBFINISHED)
462 /* get info about this block */
465 iinfo = bptr->inlineinfo;
467 /* initialize javalocals at the start of this block */
469 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
471 /* iterate over the instructions */
474 iend = iptr + bptr->icount;
478 for (; iptr != iend; ++iptr) {
480 #if defined(ENABLE_GC_CACAO)
482 md = iptr->sx.s23.s3.bte->md;
484 COUNT_javalocals(javalocals, m, alloccount);
485 alloccount += iptr->s1.argcount;
487 alloccount -= iinfo->throughcount;
491 case ICMD_INVOKESTATIC:
492 case ICMD_INVOKESPECIAL:
493 case ICMD_INVOKEVIRTUAL:
494 case ICMD_INVOKEINTERFACE:
495 INSTRUCTION_GET_METHODDESC(iptr, md);
497 COUNT_javalocals(javalocals, m, alloccount);
498 alloccount += iptr->s1.argcount;
500 alloccount -= iinfo->throughcount;
508 stack_javalocals_store(iptr, javalocals);
522 case ICMD_INLINE_START:
523 iinfo = iptr->sx.s23.s3.inlineinfo;
526 COUNT_javalocals(javalocals, m, alloccount);
527 alloccount += iinfo->stackvarscount;
528 if (iinfo->synclocal != UNUSED)
532 /* javalocals may be set at next block start, or now */
533 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
536 case ICMD_INLINE_BODY:
537 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
539 jl = iinfo->javalocals_start;
541 /* get the javalocals from the following block start */
543 jl = bptr->next->javalocals;
546 COUNT_javalocals(jl, m, alloccount);
549 case ICMD_INLINE_END:
550 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
551 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
552 iinfo = iptr->sx.s23.s3.inlineinfo;
554 if (iinfo->javalocals_end)
555 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
556 iinfo = iinfo->parent;
560 if (iptr == bptr->iinstr)
562 } /* end instruction loop */
564 /* create replacement points at targets of backward branches */
565 /* We only need the replacement point there, if there is no */
566 /* replacement point inside the block. */
568 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
569 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
570 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
574 if (test > startcount) {
575 /* we don't need an extra rplpoint */
576 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
580 alloccount += bptr->indepth;
581 if (bptr->inlineinfo)
582 alloccount -= bptr->inlineinfo->throughcount;
584 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
588 } /* end basicblock loop */
590 /* if no points were found, there's nothing to do */
595 /* allocate replacement point array and allocation array */
597 rplpoints = MNEW(rplpoint, count);
598 regalloc = MNEW(rplalloc, alloccount);
601 /* initialize replacement point structs */
605 /* XXX try to share code with the counting loop! */
607 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
610 if (bptr->flags < BBFINISHED)
613 /* get info about this block */
616 iinfo = bptr->inlineinfo;
618 /* initialize javalocals at the start of this block */
620 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
622 /* create replacement points at targets of backward branches */
624 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
626 i = (iinfo) ? iinfo->throughcount : 0;
627 replace_create_replacement_point(jd, iinfo, rp++,
628 bptr->type, bptr->iinstr, &ra,
629 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
631 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
632 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
635 /* iterate over the instructions */
638 iend = iptr + bptr->icount;
640 for (; iptr != iend; ++iptr) {
642 #if defined(ENABLE_GC_CACAO)
644 md = iptr->sx.s23.s3.bte->md;
646 i = (iinfo) ? iinfo->throughcount : 0;
647 replace_create_replacement_point(jd, iinfo, rp++,
648 RPLPOINT_TYPE_CALL, iptr, &ra,
649 javalocals, iptr->sx.s23.s2.args,
650 iptr->s1.argcount - i,
655 case ICMD_INVOKESTATIC:
656 case ICMD_INVOKESPECIAL:
657 case ICMD_INVOKEVIRTUAL:
658 case ICMD_INVOKEINTERFACE:
659 INSTRUCTION_GET_METHODDESC(iptr, md);
661 i = (iinfo) ? iinfo->throughcount : 0;
662 replace_create_replacement_point(jd, iinfo, rp++,
663 RPLPOINT_TYPE_CALL, iptr, &ra,
664 javalocals, iptr->sx.s23.s2.args,
665 iptr->s1.argcount - i,
674 stack_javalocals_store(iptr, javalocals);
682 replace_create_replacement_point(jd, iinfo, rp++,
683 RPLPOINT_TYPE_RETURN, iptr, &ra,
684 NULL, &(iptr->s1.varindex), 1, 0);
688 replace_create_replacement_point(jd, iinfo, rp++,
689 RPLPOINT_TYPE_RETURN, iptr, &ra,
693 case ICMD_INLINE_START:
694 iinfo = replace_create_inline_start_replacement_point(
695 jd, rp++, iptr, &ra, javalocals);
697 /* javalocals may be set at next block start, or now */
698 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
701 case ICMD_INLINE_BODY:
702 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
704 jl = iinfo->javalocals_start;
706 /* get the javalocals from the following block start */
708 jl = bptr->next->javalocals;
710 /* create a non-trappable rplpoint */
711 replace_create_replacement_point(jd, iinfo, rp++,
712 RPLPOINT_TYPE_BODY, iptr, &ra,
714 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
717 case ICMD_INLINE_END:
718 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
719 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
720 iinfo = iptr->sx.s23.s3.inlineinfo;
722 if (iinfo->javalocals_end)
723 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
724 iinfo = iinfo->parent;
727 } /* end instruction loop */
728 } /* end basicblock loop */
730 assert((rp - rplpoints) == count);
731 assert((ra - regalloc) == alloccount);
733 /* store the data in the codeinfo */
735 code->rplpoints = rplpoints;
736 code->rplpointcount = count;
737 code->regalloc = regalloc;
738 code->regalloccount = alloccount;
739 code->globalcount = 0;
740 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
741 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
742 #if defined(HAS_ADDRESS_REGISTER_FILE)
743 code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
745 code->memuse = rd->memuse;
746 code->stackframesize = jd->cd->stackframesize;
748 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
749 REPLACE_COUNT_INC(stat_regallocs, alloccount);
751 /* everything alright */
757 /* replace_free_replacement_points *********************************************
759 Free memory used by replacement points.
762 code.............codeinfo whose replacement points should be freed.
764 *******************************************************************************/
766 void replace_free_replacement_points(codeinfo *code)
771 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
774 MFREE(code->regalloc,rplalloc,code->regalloccount);
776 code->rplpoints = NULL;
777 code->rplpointcount = 0;
778 code->regalloc = NULL;
779 code->regalloccount = 0;
780 code->globalcount = 0;
784 /******************************************************************************/
785 /* PART II: Activating / deactivating replacement points */
786 /******************************************************************************/
789 /* replace_activate_replacement_points *****************************************
791 Activate the replacement points of the given compilation unit. When this
792 function returns, the replacement points are "armed", so each thread
793 reaching one of the points will enter the replacement mechanism.
796 code.............codeinfo of which replacement points should be
798 mappable.........if true, only mappable replacement points are
801 *******************************************************************************/
803 void replace_activate_replacement_points(codeinfo *code, bool mappable)
811 assert(code->savedmcode == NULL);
813 /* count trappable replacement points */
817 i = code->rplpointcount;
818 rp = code->rplpoints;
820 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
825 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
831 /* allocate buffer for saved machine code */
833 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
834 code->savedmcode = savedmcode;
835 savedmcode += count * REPLACEMENT_PATCH_SIZE;
837 /* activate trappable replacement points */
838 /* (in reverse order to handle overlapping points within basic blocks) */
840 i = code->rplpointcount;
841 rp = code->rplpoints + i;
843 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
845 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
850 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
853 DOLOG( printf("activate replacement point:\n");
854 replace_replacement_point_println(rp, 1); fflush(stdout); );
856 savedmcode -= REPLACEMENT_PATCH_SIZE;
858 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
859 md_patch_replacement_point(code, index, rp, savedmcode);
861 rp->flags |= RPLPOINT_FLAG_ACTIVE;
864 assert(savedmcode == code->savedmcode);
868 /* replace_deactivate_replacement_points ***************************************
870 Deactivate a replacement points in the given compilation unit.
871 When this function returns, the replacement points will be "un-armed",
872 that is a each thread reaching a point will just continue normally.
875 code.............the compilation unit
877 *******************************************************************************/
879 void replace_deactivate_replacement_points(codeinfo *code)
886 if (code->savedmcode == NULL) {
887 /* disarm countdown points by patching the branches */
889 i = code->rplpointcount;
890 rp = code->rplpoints;
892 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
893 == RPLPOINT_FLAG_COUNTDOWN)
896 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
903 assert(code->savedmcode != NULL);
904 savedmcode = code->savedmcode;
906 /* de-activate each trappable replacement point */
908 i = code->rplpointcount;
909 rp = code->rplpoints;
912 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
917 DOLOG( printf("deactivate replacement point:\n");
918 replace_replacement_point_println(rp, 1); fflush(stdout); );
920 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
921 md_patch_replacement_point(code, -1, rp, savedmcode);
924 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
926 savedmcode += REPLACEMENT_PATCH_SIZE;
929 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
931 /* free saved machine code */
933 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
934 code->savedmcode = NULL;
938 /******************************************************************************/
939 /* PART III: The replacement mechanism */
940 /******************************************************************************/
943 /* replace_read_value **********************************************************
945 Read a value with the given allocation from the execution state.
948 es...............execution state
949 ra...............allocation
950 javaval..........where to put the value
953 *javaval.........the value
955 *******************************************************************************/
957 static void replace_read_value(executionstate_t *es,
959 replace_val_t *javaval)
961 if (ra->flags & INMEMORY) {
962 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
963 #ifdef HAS_4BYTE_STACKSLOT
964 if (IS_2_WORD_TYPE(ra->type)) {
965 javaval->l = *(u8*)(es->sp + ra->regoff);
969 javaval->p = *(ptrint*)(es->sp + ra->regoff);
970 #ifdef HAS_4BYTE_STACKSLOT
975 /* allocated register */
976 if (IS_FLT_DBL_TYPE(ra->type)) {
977 javaval->d = es->fltregs[ra->regoff];
979 if (ra->type == TYPE_FLT)
980 javaval->f = javaval->d;
982 #if defined(HAS_ADDRESS_REGISTER_FILE)
983 else if (IS_ADR_TYPE(ra->type)) {
984 javaval->p = es->adrregs[ra->regoff];
988 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
989 if (ra->type == TYPE_LNG) {
990 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
991 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
994 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
995 javaval->p = es->intregs[ra->regoff];
1001 /* replace_write_value *********************************************************
1003 Write a value to the given allocation in the execution state.
1006 es...............execution state
1007 ra...............allocation
1008 *javaval.........the value
1010 *******************************************************************************/
1012 static void replace_write_value(executionstate_t *es,
1014 replace_val_t *javaval)
1016 if (ra->flags & INMEMORY) {
1017 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1018 #ifdef HAS_4BYTE_STACKSLOT
1019 if (IS_2_WORD_TYPE(ra->type)) {
1020 *(u8*)(es->sp + ra->regoff) = javaval->l;
1024 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1025 #ifdef HAS_4BYTE_STACKSLOT
1030 /* allocated register */
1033 es->fltregs[ra->regoff] = (double) javaval->f;
1036 es->fltregs[ra->regoff] = javaval->d;
1038 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1040 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1041 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1044 #if defined(HAS_ADDRESS_REGISTER_FILE)
1046 es->adrregs[ra->regoff] = javaval->p;
1049 es->intregs[ra->regoff] = javaval->p;
1055 /* replace_new_sourceframe *****************************************************
1057 Allocate a new source frame and insert it at the front of the frame list.
1060 ss...............the source state
1063 ss->frames.......set to new frame (the new head of the frame list).
1066 returns the new frame
1068 *******************************************************************************/
1070 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1072 sourceframe_t *frame;
1074 frame = DNEW(sourceframe_t);
1075 MZERO(frame, sourceframe_t, 1);
1077 frame->down = ss->frames;
1084 /* replace_read_executionstate *************************************************
1086 Read a source frame from the given executions state.
1087 The new source frame is pushed to the front of the frame list of the
1091 rp...............replacement point at which `es` was taken
1092 es...............execution state
1093 ss...............the source state to add the source frame to
1094 topframe.........true, if the first (top-most) source frame on the
1098 *ss..............the source state with the newly created source frame
1101 *******************************************************************************/
1103 static s4 replace_normalize_type_map[] = {
1104 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1105 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1106 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1107 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1108 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1109 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1110 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1114 static void replace_read_executionstate(rplpoint *rp,
1115 executionstate_t *es,
1124 sourceframe_t *frame;
1127 stackslot_t *basesp;
1129 code = code_find_codeinfo_for_pc(rp->pc);
1131 topslot = TOP_IS_NORMAL;
1135 sp = (stackslot_t *) es->sp;
1137 /* in some cases the top stack slot is passed in REG_ITMP1 */
1139 if (rp->type == BBTYPE_EXH) {
1140 topslot = TOP_IS_IN_ITMP1;
1143 /* calculate base stack pointer */
1145 basesp = sp + code->stackframesize;
1147 /* create the source frame */
1149 frame = replace_new_sourceframe(ss);
1150 frame->method = rp->method;
1152 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1153 frame->type = replace_normalize_type_map[rp->type];
1155 frame->fromcode = code;
1157 /* read local variables */
1159 count = m->maxlocals;
1160 frame->javalocalcount = count;
1161 frame->javalocals = DMNEW(replace_val_t, count);
1162 frame->javalocaltype = DMNEW(u1, count);
1164 /* mark values as undefined */
1165 for (i=0; i<count; ++i) {
1166 #if !defined(NDEBUG)
1167 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1169 frame->javalocaltype[i] = TYPE_VOID;
1172 /* some entries in the intregs array are not meaningful */
1173 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1174 #if !defined(NDEBUG)
1175 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1177 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1179 #endif /* !defined(NDEBUG) */
1181 /* read javalocals */
1183 count = rp->regalloccount;
1186 while (count && (i = ra->index) >= 0) {
1187 assert(i < m->maxlocals);
1188 frame->javalocaltype[i] = ra->type;
1189 if (ra->type == TYPE_RET)
1190 frame->javalocals[i].i = ra->regoff;
1192 replace_read_value(es, ra, frame->javalocals + i);
1197 /* read instance, if this is the first rplpoint */
1199 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1200 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1202 /* we are at the start of the method body, so if local 0 is set, */
1203 /* it is the instance. */
1204 if (frame->javalocaltype[0] == TYPE_ADR)
1205 frame->instance = frame->javalocals[0];
1210 md = rp->method->parseddesc;
1212 assert(md->paramcount >= 1);
1213 instra.type = TYPE_ADR;
1214 instra.regoff = md->params[0].regoff;
1215 if (md->params[0].inmemory) {
1216 instra.flags = INMEMORY;
1217 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1222 replace_read_value(es, &instra, &(frame->instance));
1225 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1227 /* read stack slots */
1229 frame->javastackdepth = count;
1230 frame->javastack = DMNEW(replace_val_t, count);
1231 frame->javastacktype = DMNEW(u1, count);
1233 #if !defined(NDEBUG)
1234 /* mark values as undefined */
1235 for (i=0; i<count; ++i) {
1236 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1237 frame->javastacktype[i] = TYPE_VOID;
1239 #endif /* !defined(NDEBUG) */
1243 /* the first stack slot is special in SBR and EXH blocks */
1245 if (topslot == TOP_IS_ON_STACK) {
1248 assert(ra->index == RPLALLOC_STACK);
1249 assert(ra->type == TYPE_ADR);
1250 frame->javastack[i].p = sp[-1];
1251 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1256 else if (topslot == TOP_IS_IN_ITMP1) {
1259 assert(ra->index == RPLALLOC_STACK);
1260 assert(ra->type == TYPE_ADR);
1261 frame->javastack[i].p = es->intregs[REG_ITMP1];
1262 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1267 else if (topslot == TOP_IS_VOID) {
1270 assert(ra->index == RPLALLOC_STACK);
1271 frame->javastack[i].l = 0;
1272 frame->javastacktype[i] = TYPE_VOID;
1278 /* read remaining stack slots */
1280 for (; count--; ra++) {
1281 if (ra->index == RPLALLOC_SYNC) {
1282 assert(rp->type == RPLPOINT_TYPE_INLINE);
1284 /* only read synchronization slots when traversing an inline point */
1287 sourceframe_t *calleeframe = frame->down;
1288 assert(calleeframe);
1289 assert(calleeframe->syncslotcount == 0);
1290 assert(calleeframe->syncslots == NULL);
1292 calleeframe->syncslotcount = 1;
1293 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1294 replace_read_value(es,ra,calleeframe->syncslots);
1297 frame->javastackdepth--;
1301 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1303 /* do not read parameters of calls down the call chain */
1305 if (!topframe && ra->index == RPLALLOC_PARAM) {
1306 frame->javastackdepth--;
1309 if (ra->type == TYPE_RET)
1310 frame->javastack[i].i = ra->regoff;
1312 replace_read_value(es,ra,frame->javastack + i);
1313 frame->javastacktype[i] = ra->type;
1320 /* replace_write_executionstate ************************************************
1322 Pop a source frame from the front of the frame list of the given source state
1323 and write its values into the execution state.
1326 rp...............replacement point for which execution state should be
1328 es...............the execution state to modify
1329 ss...............the given source state
1330 topframe.........true, if this is the last (top-most) source frame to be
1334 *es..............the execution state derived from the source state
1336 *******************************************************************************/
1338 static void replace_write_executionstate(rplpoint *rp,
1339 executionstate_t *es,
1348 sourceframe_t *frame;
1351 stackslot_t *basesp;
1353 code = code_find_codeinfo_for_pc(rp->pc);
1355 topslot = TOP_IS_NORMAL;
1357 /* pop a source frame */
1361 ss->frames = frame->down;
1363 /* calculate stack pointer */
1365 sp = (stackslot_t *) es->sp;
1367 basesp = sp + code->stackframesize;
1369 /* in some cases the top stack slot is passed in REG_ITMP1 */
1371 if (rp->type == BBTYPE_EXH) {
1372 topslot = TOP_IS_IN_ITMP1;
1375 /* write javalocals */
1378 count = rp->regalloccount;
1380 while (count && (i = ra->index) >= 0) {
1381 assert(i < m->maxlocals);
1382 assert(i < frame->javalocalcount);
1383 assert(ra->type == frame->javalocaltype[i]);
1384 if (ra->type == TYPE_RET) {
1385 /* XXX assert that it matches this rplpoint */
1388 replace_write_value(es, ra, frame->javalocals + i);
1393 /* write stack slots */
1397 /* the first stack slot is special in SBR and EXH blocks */
1399 if (topslot == TOP_IS_ON_STACK) {
1402 assert(ra->index == RPLALLOC_STACK);
1403 assert(i < frame->javastackdepth);
1404 assert(frame->javastacktype[i] == TYPE_ADR);
1405 sp[-1] = frame->javastack[i].p;
1410 else if (topslot == TOP_IS_IN_ITMP1) {
1413 assert(ra->index == RPLALLOC_STACK);
1414 assert(i < frame->javastackdepth);
1415 assert(frame->javastacktype[i] == TYPE_ADR);
1416 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1421 else if (topslot == TOP_IS_VOID) {
1424 assert(ra->index == RPLALLOC_STACK);
1425 assert(i < frame->javastackdepth);
1426 assert(frame->javastacktype[i] == TYPE_VOID);
1432 /* write remaining stack slots */
1434 for (; count--; ra++) {
1435 if (ra->index == RPLALLOC_SYNC) {
1436 assert(rp->type == RPLPOINT_TYPE_INLINE);
1438 /* only write synchronization slots when traversing an inline point */
1441 assert(frame->down);
1442 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1443 assert(frame->down->syncslots != NULL);
1445 replace_write_value(es,ra,frame->down->syncslots);
1450 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1452 /* do not write parameters of calls down the call chain */
1454 if (!topframe && ra->index == RPLALLOC_PARAM) {
1458 assert(i < frame->javastackdepth);
1459 assert(ra->type == frame->javastacktype[i]);
1460 if (ra->type == TYPE_RET) {
1461 /* XXX assert that it matches this rplpoint */
1464 replace_write_value(es,ra,frame->javastack + i);
1476 /* replace_pop_activation_record ***********************************************
1478 Peel a stack frame from the execution state.
1480 *** This function imitates the effects of the method epilog ***
1481 *** and returning from the method call. ***
1484 es...............execution state
1485 frame............source frame, receives synchronization slots
1488 *es..............the execution state after popping the stack frame
1490 *******************************************************************************/
1492 u1* replace_pop_activation_record(executionstate_t *es,
1493 sourceframe_t *frame)
1501 stackslot_t *basesp;
1507 /* read the return address */
1509 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1510 if (CODE_IS_LEAFMETHOD(es->code))
1511 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1514 ra = md_stacktrace_get_returnaddress(es->sp,
1515 SIZE_OF_STACKSLOT * es->code->stackframesize);
1517 DOLOG( printf("return address: %p\n", (void*)ra); );
1521 /* calculate the base of the stack frame */
1523 sp = (stackslot_t *) es->sp;
1524 basesp = sp + es->code->stackframesize;
1526 /* read slots used for synchronization */
1528 assert(frame->syncslotcount == 0);
1529 assert(frame->syncslots == NULL);
1530 count = code_get_sync_slot_count(es->code);
1531 frame->syncslotcount = count;
1532 frame->syncslots = DMNEW(replace_val_t, count);
1533 for (i=0; i<count; ++i) {
1534 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1537 /* restore return address, if part of frame */
1539 #if defined(REPLACE_RA_TOP_OF_FRAME)
1540 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1541 if (!CODE_IS_LEAFMETHOD(es->code))
1543 es->intregs[REPLACE_REG_RA] = *--basesp;
1544 #endif /* REPLACE_RA_TOP_OF_FRAME */
1546 #if defined(REPLACE_RA_LINKAGE_AREA)
1547 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1548 if (!CODE_IS_LEAFMETHOD(es->code))
1550 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1551 #endif /* REPLACE_RA_LINKAGE_AREA */
1553 /* restore saved int registers */
1556 for (i=0; i<es->code->savedintcount; ++i) {
1557 while (nregdescint[--reg] != REG_SAV)
1559 es->intregs[reg] = *--basesp;
1562 /* restore saved flt registers */
1566 for (i=0; i<es->code->savedfltcount; ++i) {
1567 while (nregdescfloat[--reg] != REG_SAV)
1569 basesp -= STACK_SLOTS_PER_FLOAT;
1570 es->fltregs[reg] = *(double*)basesp;
1573 #if defined(HAS_ADDRESS_REGISTER_FILE)
1574 /* restore saved adr registers */
1577 for (i=0; i<es->code->savedadrcount; ++i) {
1578 while (nregdescadr[--reg] != REG_SAV)
1580 es->adrregs[reg] = *--basesp;
1584 /* adjust the stackpointer */
1586 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1588 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1589 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1592 /* Set the new pc. Subtract one so we do not hit the replacement point */
1593 /* of the instruction following the call, if there is one. */
1597 /* find the new codeinfo */
1599 pv = md_codegen_get_pv_from_pc(ra);
1601 DOLOG( printf("PV = %p\n", (void*) pv); );
1603 if (pv == NULL) /* XXX can this really happen? */
1606 code = *(codeinfo **)(pv + CodeinfoPointer);
1608 DOLOG( printf("CODE = %p\n", (void*) code); );
1610 /* return NULL if we reached native code */
1615 /* in debugging mode clobber non-saved registers */
1617 #if !defined(NDEBUG)
1619 for (i=0; i<INT_REG_CNT; ++i)
1620 if ((nregdescint[i] != REG_SAV)
1622 && (i != REPLACE_REG_RA)
1625 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1626 for (i=0; i<FLT_REG_CNT; ++i)
1627 if (nregdescfloat[i] != REG_SAV)
1628 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1629 # if defined(HAS_ADDRESS_REGISTER_FILE)
1630 for (i=0; i<ADR_REG_CNT; ++i)
1631 if (nregdescadr[i] != REG_SAV)
1632 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1634 #endif /* !defined(NDEBUG) */
1636 return (code) ? ra : NULL;
1640 /* replace_patch_method_pointer ************************************************
1642 Patch a method pointer (may be in code, data segment, vftbl, or interface
1646 mpp..............address of the method pointer to patch
1647 entrypoint.......the new entrypoint of the method
1648 kind.............kind of call to patch, used only for debugging
1650 *******************************************************************************/
1652 static void replace_patch_method_pointer(methodptr *mpp,
1653 methodptr entrypoint,
1656 #if !defined(NDEBUG)
1661 DOLOG( printf("patch method pointer from: %p to %p\n",
1662 (void*) *mpp, (void*)entrypoint); );
1664 #if !defined(NDEBUG)
1665 oldcode = *(codeinfo **)((u1*)(*mpp) + CodeinfoPointer);
1666 newcode = *(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer);
1668 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1669 method_println(oldcode->m);
1670 printf("\t with %p ", (void*) newcode);
1671 method_println(newcode->m); );
1673 assert(oldcode->m == newcode->m);
1676 /* write the new entrypoint */
1678 *mpp = (methodptr) entrypoint;
1682 /* replace_patch_class *********************************************************
1684 Patch a method in the given class.
1687 vftbl............vftbl of the class
1688 m................the method to patch
1689 oldentrypoint....the old entrypoint to replace
1690 entrypoint.......the new entrypoint
1692 *******************************************************************************/
1694 void replace_patch_class(vftbl_t *vftbl,
1703 /* patch the vftbl of the class */
1705 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1709 /* patch the interface tables */
1711 assert(oldentrypoint);
1713 for (i=0; i < vftbl->interfacetablelength; ++i) {
1714 mpp = vftbl->interfacetable[-i];
1715 mppend = mpp + vftbl->interfacevftbllength[i];
1716 for (; mpp != mppend; ++mpp)
1717 if (*mpp == oldentrypoint) {
1718 replace_patch_method_pointer(mpp, entrypoint, "interface");
1724 /* replace_patch_class_hierarchy ***********************************************
1726 Patch a method in all loaded classes.
1729 m................the method to patch
1730 oldentrypoint....the old entrypoint to replace
1731 entrypoint.......the new entrypoint
1733 *******************************************************************************/
1735 struct replace_patch_data_t {
1741 #define CODEINFO_OF_CODE(entrypoint) \
1742 (*(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer))
1744 #define METHOD_OF_CODE(entrypoint) \
1745 (CODEINFO_OF_CODE(entrypoint)->m)
1747 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1749 vftbl_t *vftbl = c->vftbl;
1752 && vftbl->vftbllength > pd->m->vftblindex
1753 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1754 && METHOD_OF_CODE(vftbl->table[pd->m->vftblindex]) == pd->m)
1756 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1760 void replace_patch_class_hierarchy(methodinfo *m,
1764 struct replace_patch_data_t pd;
1767 pd.oldentrypoint = oldentrypoint;
1768 pd.entrypoint = entrypoint;
1770 DOLOG_SHORT( printf("patching class hierarchy: ");
1771 method_println(m); );
1773 classcache_foreach_loaded_class(
1774 (classcache_foreach_functionptr_t) &replace_patch_callback,
1779 /* replace_patch_future_calls **************************************************
1781 Analyse a call site and depending on the kind of call patch the call, the
1782 virtual function table, or the interface table.
1785 ra...............return address pointing after the call site
1786 callerframe......source frame of the caller
1787 calleeframe......source frame of the callee, must have been mapped
1789 *******************************************************************************/
1791 void replace_patch_future_calls(u1 *ra,
1792 sourceframe_t *callerframe,
1793 sourceframe_t *calleeframe)
1796 methodptr entrypoint;
1797 methodptr oldentrypoint;
1800 codeinfo *calleecode;
1801 methodinfo *calleem;
1806 assert(callerframe->down == calleeframe);
1808 /* get the new codeinfo and the method that shall be entered */
1810 calleecode = calleeframe->tocode;
1813 calleem = calleeframe->method;
1814 assert(calleem == calleecode->m);
1816 entrypoint = (methodptr) calleecode->entrypoint;
1818 /* check if we are at an method entry rplpoint at the innermost frame */
1820 atentry = (calleeframe->down == NULL)
1821 && !(calleem->flags & ACC_STATIC)
1822 && (calleeframe->fromrp->id == 0); /* XXX */
1824 /* get the position to patch, in case it was a statically bound call */
1826 sfi.pv = callerframe->fromcode->entrypoint;
1827 patchpos = md_get_method_patch_address(ra, &sfi, NULL);
1829 if (patchpos == NULL) {
1830 /* the call was dispatched dynamically */
1832 /* we can only patch such calls if we are at the entry point */
1837 assert((calleem->flags & ACC_STATIC) == 0);
1839 oldentrypoint = calleeframe->fromcode->entrypoint;
1841 /* we need to know the instance */
1843 if (!calleeframe->instance.a) {
1844 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1845 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1851 obj = calleeframe->instance.a;
1854 assert(vftbl->class->vftbl == vftbl);
1856 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1858 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1861 /* the call was statically bound */
1863 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1868 /* replace_push_activation_record **********************************************
1870 Push a stack frame onto the execution state.
1872 *** This function imitates the effects of a call and the ***
1873 *** method prolog of the callee. ***
1876 es...............execution state
1877 rpcall...........the replacement point at the call site
1878 callerframe......source frame of the caller, or NULL for creating the
1880 calleeframe......source frame of the callee, must have been mapped
1883 *es..............the execution state after pushing the stack frame
1885 *******************************************************************************/
1887 void replace_push_activation_record(executionstate_t *es,
1889 sourceframe_t *callerframe,
1890 sourceframe_t *calleeframe)
1895 stackslot_t *basesp;
1898 codeinfo *calleecode;
1901 assert(!rpcall || callerframe);
1902 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1903 assert(!rpcall || rpcall == callerframe->torp);
1904 assert(calleeframe);
1905 assert(!callerframe || calleeframe == callerframe->down);
1907 /* the compilation unit we are entering */
1909 calleecode = calleeframe->tocode;
1912 /* calculate the return address */
1915 ra = rpcall->pc + rpcall->callsize;
1917 ra = es->pc + 1 /* XXX this is ugly */;
1919 /* write the return address */
1921 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1922 es->sp -= SIZE_OF_STACKSLOT;
1924 *((stackslot_t *)es->sp) = (stackslot_t) ra;
1925 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1927 #if defined(REPLACE_REG_RA)
1928 es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1931 /* we move into a new code unit */
1933 es->code = calleecode;
1935 /* set the new pc XXX not needed? */
1937 es->pc = calleecode->entrypoint;
1939 /* build the stackframe */
1941 DOLOG( printf("building stackframe of %d words at %p\n",
1942 calleecode->stackframesize, (void*)es->sp); );
1944 sp = (stackslot_t *) es->sp;
1947 sp -= calleecode->stackframesize;
1950 /* in debug mode, invalidate stack frame first */
1952 /* XXX may not invalidate linkage area used by native code! */
1953 #if !defined(NDEBUG) && 0
1954 for (i=0; i<(basesp - sp); ++i) {
1955 sp[i] = 0xdeaddeadU;
1959 /* save the return address register */
1961 #if defined(REPLACE_RA_TOP_OF_FRAME)
1962 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1963 if (!CODE_IS_LEAFMETHOD(calleecode))
1965 *--basesp = (ptrint) ra;
1966 #endif /* REPLACE_RA_TOP_OF_FRAME */
1968 #if defined(REPLACE_RA_LINKAGE_AREA)
1969 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1970 if (!CODE_IS_LEAFMETHOD(calleecode))
1972 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1973 #endif /* REPLACE_RA_LINKAGE_AREA */
1975 /* save int registers */
1978 for (i=0; i<calleecode->savedintcount; ++i) {
1979 while (nregdescint[--reg] != REG_SAV)
1981 *--basesp = es->intregs[reg];
1983 /* XXX may not clobber saved regs used by native code! */
1984 #if !defined(NDEBUG) && 0
1985 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1989 /* save flt registers */
1993 for (i=0; i<calleecode->savedfltcount; ++i) {
1994 while (nregdescfloat[--reg] != REG_SAV)
1996 basesp -= STACK_SLOTS_PER_FLOAT;
1997 *(double*)basesp = es->fltregs[reg];
1999 /* XXX may not clobber saved regs used by native code! */
2000 #if !defined(NDEBUG) && 0
2001 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
2005 #if defined(HAS_ADDRESS_REGISTER_FILE)
2006 /* save adr registers */
2009 for (i=0; i<calleecode->savedadrcount; ++i) {
2010 while (nregdescadr[--reg] != REG_SAV)
2012 *--basesp = es->adrregs[reg];
2014 /* XXX may not clobber saved regs used by native code! */
2015 #if !defined(NDEBUG) && 0
2016 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
2021 /* write slots used for synchronization */
2023 count = code_get_sync_slot_count(calleecode);
2024 assert(count == calleeframe->syncslotcount);
2025 for (i=0; i<count; ++i) {
2026 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2031 es->pv = calleecode->entrypoint;
2033 /* redirect future invocations */
2035 if (callerframe && rpcall) {
2036 #if defined(REPLACE_PATCH_ALL)
2037 if (rpcall->type == callerframe->fromrp->type)
2039 if (rpcall == callerframe->fromrp)
2041 replace_patch_future_calls(ra, callerframe, calleeframe);
2046 /* replace_find_replacement_point **********************************************
2048 Find the replacement point in the given code corresponding to the
2049 position given in the source frame.
2052 code.............the codeinfo in which to search the rplpoint
2053 frame............the source frame defining the position to look for
2054 parent...........parent replacement point to match
2057 the replacement point
2059 *******************************************************************************/
2061 rplpoint * replace_find_replacement_point(codeinfo *code,
2062 sourceframe_t *frame,
2075 DOLOG( printf("searching replacement point for:\n");
2076 replace_source_frame_println(frame); );
2080 DOLOG( printf("code = %p\n", (void*)code); );
2082 rp = code->rplpoints;
2083 i = code->rplpointcount;
2085 if (rp->id == frame->id && rp->method == frame->method
2086 && rp->parent == parent
2087 && replace_normalize_type_map[rp->type] == frame->type)
2089 /* check if returnAddresses match */
2090 /* XXX optimize: only do this if JSRs in method */
2091 DOLOG( printf("checking match for:");
2092 replace_replacement_point_println(rp, 1); fflush(stdout); );
2095 for (j = rp->regalloccount; j--; ++ra) {
2096 if (ra->type == TYPE_RET) {
2097 if (ra->index == RPLALLOC_STACK) {
2098 assert(stacki < frame->javastackdepth);
2099 if (frame->javastack[stacki].i != ra->regoff)
2104 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2105 if (frame->javalocals[ra->index].i != ra->regoff)
2118 #if !defined(NDEBUG)
2119 printf("candidate replacement points were:\n");
2120 rp = code->rplpoints;
2121 i = code->rplpointcount;
2123 replace_replacement_point_println(rp, 1);
2127 vm_abort("no matching replacement point found");
2128 return NULL; /* NOT REACHED */
2132 /* replace_find_replacement_point_for_pc ***************************************
2134 Find the nearest replacement point at or before the given PC.
2137 code.............compilation unit the PC is in
2138 pc...............the machine code PC
2141 the replacement point found, or
2142 NULL if no replacement point was found
2144 *******************************************************************************/
2146 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2152 DOLOG( printf("searching for rp in %p ", (void*)code);
2153 method_println(code->m);
2154 printf("PC = %p\n", (void*)pc); );
2158 rp = code->rplpoints;
2159 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2160 DOLOG( replace_replacement_point_println(rp, 2); );
2165 assert(found == NULL || found->pc + found->callsize >= pc);
2171 /* replace_pop_native_frame ****************************************************
2173 Unroll a native frame in the execution state and create a source frame
2177 es...............current execution state
2178 ss...............the current source state
2179 sfi..............stackframeinfo for the native frame
2182 es...............execution state after unrolling the native frame
2183 ss...............gets the added native source frame
2185 *******************************************************************************/
2187 static void replace_pop_native_frame(executionstate_t *es,
2189 stackframeinfo *sfi)
2191 sourceframe_t *frame;
2197 frame = replace_new_sourceframe(ss);
2201 /* remember pc and size of native frame */
2203 frame->nativepc = es->pc;
2204 frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2205 assert(frame->nativeframesize >= 0);
2207 /* remember values of saved registers */
2210 for (i=0; i<INT_REG_CNT; ++i) {
2211 if (nregdescint[i] == REG_SAV)
2212 frame->nativesavint[j++] = es->intregs[i];
2216 for (i=0; i<FLT_REG_CNT; ++i) {
2217 if (nregdescfloat[i] == REG_SAV)
2218 frame->nativesavflt[j++] = es->fltregs[i];
2221 #if defined(HAS_ADDRESS_REGISTER_FILE)
2223 for (i=0; i<ADR_REG_CNT; ++i) {
2224 if (nregdescadr[i] == REG_SAV)
2225 frame->nativesavadr[j++] = es->adrregs[i];
2229 /* restore saved registers */
2231 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2233 for (i=0; i<INT_REG_CNT; ++i) {
2234 if (nregdescint[i] == REG_SAV)
2235 es->intregs[i] = sfi->intregs[j++];
2238 /* XXX we don't have them, yet, in the sfi, so clear them */
2240 for (i=0; i<INT_REG_CNT; ++i) {
2241 if (nregdescint[i] == REG_SAV)
2246 /* XXX we don't have float registers in the sfi, so clear them */
2248 for (i=0; i<FLT_REG_CNT; ++i) {
2249 if (nregdescfloat[i] == REG_SAV)
2250 es->fltregs[i] = 0.0;
2253 #if defined(HAS_ADDRESS_REGISTER_FILE)
2254 # if defined(ENABLE_GC_CACAO)
2256 for (i=0; i<ADR_REG_CNT; ++i) {
2257 if (nregdescadr[i] == REG_SAV)
2258 es->adrregs[i] = sfi->adrregs[j++];
2261 for (i=0; i<ADR_REG_CNT; ++i) {
2262 if (nregdescadr[i] == REG_SAV)
2268 /* restore pv, pc, and sp */
2270 if (sfi->pv == NULL) {
2271 /* frame of a native function call */
2272 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2277 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2280 /* find the new codeinfo */
2282 DOLOG( printf("PV = %p\n", (void*) es->pv); );
2284 assert(es->pv != NULL);
2286 code = *(codeinfo **)(es->pv + CodeinfoPointer);
2288 DOLOG( printf("CODE = %p\n", (void*) code); );
2294 /* replace_push_native_frame ***************************************************
2296 Rebuild a native frame onto the execution state and remove its source frame.
2298 Note: The native frame is "rebuild" by setting fields like PC and stack
2299 pointer in the execution state accordingly. Values in the
2300 stackframeinfo may be modified, but the actual stack frame of the
2301 native code is not touched.
2304 es...............current execution state
2305 ss...............the current source state
2308 es...............execution state after re-rolling the native frame
2309 ss...............the native source frame is removed
2311 *******************************************************************************/
2313 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2315 sourceframe_t *frame;
2321 DOLOG( printf("pushing native frame\n"); );
2323 /* remove the frame from the source state */
2327 assert(REPLACE_IS_NATIVE_FRAME(frame));
2329 ss->frames = frame->down;
2331 /* assert that the native frame has not moved */
2333 assert(es->sp == frame->sfi->sp);
2335 /* update saved registers in the stackframeinfo */
2337 #if defined(ENABLE_GC_CACAO)
2339 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2340 for (i=0; i<INT_REG_CNT; ++i) {
2341 if (nregdescint[i] == REG_SAV)
2342 frame->sfi->intregs[j++] = es->intregs[i];
2345 for (i=0; i<ADR_REG_CNT; ++i) {
2346 if (nregdescadr[i] == REG_SAV)
2347 frame->sfi->adrregs[j++] = es->adrregs[i];
2351 /* XXX leave float registers untouched here */
2354 /* restore saved registers */
2357 for (i=0; i<INT_REG_CNT; ++i) {
2358 if (nregdescint[i] == REG_SAV)
2359 es->intregs[i] = frame->nativesavint[j++];
2363 for (i=0; i<FLT_REG_CNT; ++i) {
2364 if (nregdescfloat[i] == REG_SAV)
2365 es->fltregs[i] = frame->nativesavflt[j++];
2368 #if defined(HAS_ADDRESS_REGISTER_FILE)
2370 for (i=0; i<ADR_REG_CNT; ++i) {
2371 if (nregdescadr[i] == REG_SAV)
2372 es->adrregs[i] = frame->nativesavadr[j++];
2376 /* skip the native frame on the machine stack */
2378 es->sp -= frame->nativeframesize;
2380 /* set the pc the next frame must return to */
2382 es->pc = frame->nativepc;
2386 /* replace_recover_source_state ************************************************
2388 Recover the source state from the given replacement point and execution
2392 rp...............replacement point that has been reached, if any
2393 sfi..............stackframeinfo, if called from native code
2394 es...............execution state at the replacement point rp
2399 *******************************************************************************/
2401 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2402 stackframeinfo *sfi,
2403 executionstate_t *es)
2408 #if defined(REPLACE_STATISTICS)
2412 /* create the source frame structure in dump memory */
2414 ss = DNEW(sourcestate_t);
2417 /* each iteration of the loop recovers one source frame */
2424 DOLOG( replace_executionstate_println(es); );
2426 /* if we are not at a replacement point, it is a native frame */
2429 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2432 replace_pop_native_frame(es, ss, sfi);
2435 if (es->code == NULL)
2438 goto after_machine_frame;
2441 /* read the values for this source frame from the execution state */
2443 DOLOG( printf("recovering source state for%s:\n",
2444 (ss->frames == NULL) ? " TOPFRAME" : "");
2445 replace_replacement_point_println(rp, 1); );
2447 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2449 #if defined(ENABLE_VMLOG)
2450 vmlog_cacao_unrol_method(ss->frames->method);
2453 #if defined(REPLACE_STATISTICS)
2454 REPLACE_COUNT(stat_frames);
2456 replace_statistics_source_frame(ss->frames);
2459 /* in locked areas (below native frames), identity map the frame */
2462 ss->frames->torp = ss->frames->fromrp;
2463 ss->frames->tocode = ss->frames->fromcode;
2466 /* unroll to the next (outer) frame */
2469 /* this frame is in inlined code */
2471 DOLOG( printf("INLINED!\n"); );
2475 assert(rp->type == RPLPOINT_TYPE_INLINE);
2476 REPLACE_COUNT(stat_unroll_inline);
2479 /* this frame had been called at machine-level. pop it. */
2481 DOLOG( printf("UNWIND\n"); );
2483 ra = replace_pop_activation_record(es, ss->frames);
2485 DOLOG( printf("REACHED NATIVE CODE\n"); );
2489 #if !defined(ENABLE_GC_CACAO)
2490 break; /* XXX remove to activate native frames */
2495 /* find the replacement point at the call site */
2497 after_machine_frame:
2498 rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2501 vm_abort("could not find replacement point while unrolling call");
2503 DOLOG( printf("found replacement point.\n");
2504 replace_replacement_point_println(rp, 1); );
2506 assert(rp->type == RPLPOINT_TYPE_CALL);
2507 REPLACE_COUNT(stat_unroll_call);
2509 } /* end loop over source frames */
2511 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2517 /* replace_map_source_state ****************************************************
2519 Map each source frame in the given source state to a target replacement
2520 point and compilation unit. If no valid code is available for a source
2521 frame, it is (re)compiled.
2524 ss...............the source state
2527 ss...............the source state, modified: The `torp` and `tocode`
2528 fields of each source frame are set.
2531 true.............everything went ok
2532 false............an exception has been thrown
2534 *******************************************************************************/
2536 static bool replace_map_source_state(sourcestate_t *ss)
2538 sourceframe_t *frame;
2541 rplpoint *parent; /* parent of inlined rplpoint */
2542 #if defined(REPLACE_STATISTICS)
2549 /* iterate over the source frames from outermost to innermost */
2551 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2553 /* XXX skip native frames */
2555 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2560 /* map frames which are not already mapped */
2562 if (frame->tocode) {
2563 code = frame->tocode;
2568 assert(frame->torp == NULL);
2570 if (parent == NULL) {
2571 /* find code for this frame */
2573 #if defined(REPLACE_STATISTICS)
2574 oldcode = frame->method->code;
2576 /* request optimization of hot methods and their callers */
2578 if (frame->method->hitcountdown < 0
2579 || (frame->down && frame->down->method->hitcountdown < 0))
2580 jit_request_optimization(frame->method);
2582 code = jit_get_current_code(frame->method);
2585 return false; /* exception */
2587 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2592 /* map this frame */
2594 rp = replace_find_replacement_point(code, frame, parent);
2596 frame->tocode = code;
2600 if (rp->type == RPLPOINT_TYPE_CALL) {
2613 /* replace_map_source_state_identity *******************************************
2615 Map each source frame in the given source state to the same replacement
2616 point and compilation unit it was derived from. This is mainly used for
2620 ss...............the source state
2623 ss...............the source state, modified: The `torp` and `tocode`
2624 fields of each source frame are set.
2626 *******************************************************************************/
2628 #if defined(ENABLE_GC_CACAO)
2629 static void replace_map_source_state_identity(sourcestate_t *ss)
2631 sourceframe_t *frame;
2633 /* iterate over the source frames from outermost to innermost */
2635 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2637 /* skip native frames */
2639 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2643 /* map frames using the identity mapping */
2645 if (frame->tocode) {
2646 assert(frame->tocode == frame->fromcode);
2647 assert(frame->torp == frame->fromrp);
2649 assert(frame->tocode == NULL);
2650 assert(frame->torp == NULL);
2651 frame->tocode = frame->fromcode;
2652 frame->torp = frame->fromrp;
2659 /* replace_build_execution_state_intern ****************************************
2661 Build an execution state for the given (mapped) source state.
2663 !!! CAUTION: This function rewrites the machine stack !!!
2665 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2668 ss...............the source state. Must have been mapped by
2669 replace_map_source_state before.
2670 es...............the base execution state on which to build
2673 *es..............the new execution state
2675 *******************************************************************************/
2677 void replace_build_execution_state_intern(sourcestate_t *ss,
2678 executionstate_t *es)
2681 sourceframe_t *prevframe;
2688 while (ss->frames) {
2690 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2691 prevframe = ss->frames;
2692 replace_push_native_frame(es, ss);
2698 if (parent == NULL) {
2699 /* create a machine-level stack frame */
2701 DOLOG( printf("pushing activation record for:\n");
2702 if (rp) replace_replacement_point_println(rp, 1);
2703 else printf("\tfirst frame\n"); );
2705 replace_push_activation_record(es, rp, prevframe, ss->frames);
2707 DOLOG( replace_executionstate_println(es); );
2710 rp = ss->frames->torp;
2713 DOLOG( printf("creating execution state for%s:\n",
2714 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2715 replace_replacement_point_println(ss->frames->fromrp, 1);
2716 replace_replacement_point_println(rp, 1); );
2718 es->code = ss->frames->tocode;
2719 prevframe = ss->frames;
2721 #if defined(ENABLE_VMLOG)
2722 vmlog_cacao_rerol_method(ss->frames->method);
2725 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2727 DOLOG( replace_executionstate_println(es); );
2729 if (rp->type == RPLPOINT_TYPE_CALL) {
2740 /* replace_build_execution_state ***********************************************
2742 This function contains the final phase of replacement. It builds the new
2743 execution state, releases dump memory, and returns to the calling
2744 assembler function which finishes replacement.
2746 NOTE: This function is called from asm_replacement_in, with the stack
2747 pointer at the start of the safe stack area.
2749 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2751 CAUTION: This function and its children must not use a lot of stack!
2752 There are only REPLACE_SAFESTACK_SIZE bytes of C stack
2756 st...............the safestack contained the necessary data
2758 *******************************************************************************/
2760 void replace_build_execution_state(replace_safestack_t *st)
2762 replace_build_execution_state_intern(st->ss, &(st->es));
2764 DOLOG( replace_executionstate_println(&(st->es)); );
2766 /* release dump area */
2768 dump_release(st->dumpsize);
2770 /* new code is entered after returning */
2772 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2776 /* replace_alloc_safestack *****************************************************
2778 Allocate a safe stack area to use during the final phase of replacement.
2779 The returned area is not initialized. This must be done by the caller.
2782 a newly allocated replace_safestack_t *
2784 *******************************************************************************/
2786 static replace_safestack_t *replace_alloc_safestack()
2789 replace_safestack_t *st;
2791 mem = MNEW(u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2793 st = (replace_safestack_t *) ((ptrint)(mem + REPLACE_STACK_ALIGNMENT - 1)
2794 & ~(REPLACE_STACK_ALIGNMENT - 1));
2796 #if !defined(NDEBUG)
2797 memset(st, 0xa5, sizeof(replace_safestack_t));
2806 /* replace_free_safestack ******************************************************
2808 Free the given safestack structure, making a copy of the contained
2809 execution state before freeing it.
2811 NOTE: This function is called from asm_replacement_in.
2814 st...............the safestack to free
2815 tmpes............where to copy the execution state to
2818 *tmpes...........receives a copy of st->es
2820 *******************************************************************************/
2822 void replace_free_safestack(replace_safestack_t *st, executionstate_t *tmpes)
2826 /* copy the executionstate_t to the temporary location */
2830 /* get the memory address to free */
2834 /* destroy memory (in debug mode) */
2836 #if !defined(NDEBUG)
2837 memset(st, 0xa5, sizeof(replace_safestack_t));
2840 /* free the safe stack struct */
2842 MFREE(mem, u1, sizeof(replace_safestack_t) + REPLACE_STACK_ALIGNMENT - 1);
2846 /* replace_me_wrapper **********************************************************
2850 *******************************************************************************/
2852 bool replace_me_wrapper(u1 *pc)
2856 executionstate_t es;
2858 /* search the codeinfo for the given PC */
2860 code = code_find_codeinfo_for_pc(pc);
2863 /* search for a replacement point at the given PC */
2866 rp = replace_find_replacement_point_for_pc(code, pc);
2867 assert(rp == NULL || rp->pc == pc);
2873 for (i=0,rp2=code->rplpoints; i<code->rplpointcount; i++,rp2++) {
2880 /* check if the replacement point is active */
2882 if (rp != NULL && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
2884 /*md_replace_executionstate_read(&es, context);*/
2886 replace_me(rp, &es);
2895 /* replace_me ******************************************************************
2897 This function is called by asm_replacement_out when a thread reaches
2898 a replacement point. `replace_me` must map the execution state to the
2899 target replacement point and let execution continue there.
2901 This function never returns!
2904 rp...............replacement point that has been reached
2905 es...............execution state read by asm_replacement_out
2907 *******************************************************************************/
2909 void replace_me(rplpoint *rp, executionstate_t *es)
2911 stackframeinfo *sfi;
2913 sourceframe_t *frame;
2916 replace_safestack_t *safestack;
2917 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2918 threadobject *thread;
2922 es->code = code_find_codeinfo_for_pc(rp->pc);
2924 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2925 stat_replacements, (void*)THREADOBJECT,
2927 method_println(es->code->m); );
2929 DOLOG( replace_replacement_point_println(rp, 1);
2930 replace_executionstate_println(es); );
2932 REPLACE_COUNT(stat_replacements);
2934 /* mark start of dump memory area */
2936 dumpsize = dump_size();
2938 /* get the stackframeinfo for the current thread */
2940 sfi = STACKFRAMEINFO;
2942 /* recover source state */
2944 ss = replace_recover_source_state(rp, sfi, es);
2946 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2947 /* if there is a collection pending, we assume the replacement point should
2948 suspend this thread */
2952 thread = THREADOBJECT;
2954 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2956 /* map the sourcestate using the identity mapping */
2957 replace_map_source_state_identity(ss);
2959 /* since we enter the same method again, we turn off rps now */
2960 /* XXX michi: can we really do this? what if the rp was active before
2961 we activated it for the gc? */
2964 frame = frame->down;
2965 replace_deactivate_replacement_points(frame->tocode);
2967 /* remember executionstate and sourcestate for this thread */
2968 GC_EXECUTIONSTATE = es;
2969 GC_SOURCESTATE = ss;
2971 /* really suspend this thread now (PC = 0) */
2972 threads_suspend_ack(NULL, NULL);
2974 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2977 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2979 /* map the source state */
2981 if (!replace_map_source_state(ss))
2982 vm_abort("exception during method replacement");
2984 DOLOG( replace_sourcestate_println(ss); );
2986 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2988 /* avoid infinite loops by self-replacement */
2992 frame = frame->down;
2994 if (frame->torp == origrp) {
2996 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2998 replace_deactivate_replacement_points(frame->tocode);
3001 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
3005 /* write execution state of new code */
3007 DOLOG( replace_executionstate_println(es); );
3009 /* allocate a safe stack area and copy all needed data there */
3011 safestack = replace_alloc_safestack();
3013 safestack->es = *es;
3015 safestack->dumpsize = dumpsize;
3017 /* call the assembler code for the last phase of replacement */
3019 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__) || defined(__S390__)) && defined(ENABLE_JIT)
3020 /*asm_replacement_in(&(safestack->es), safestack);*/
3023 abort(); /* NOT REACHED */
3027 /******************************************************************************/
3028 /* NOTE: Stuff specific to the exact GC is below. */
3029 /******************************************************************************/
3031 #if defined(ENABLE_GC_CACAO)
3032 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
3034 stackframeinfo *sfi;
3035 executionstate_t *es;
3038 /* get the stackframeinfo of this thread */
3039 assert(thread == THREADOBJECT);
3040 sfi = STACKFRAMEINFO;
3042 /* create the execution state */
3043 es = DNEW(executionstate_t);
3046 es->pv = 0; /* since we are in a native, PV is invalid! */
3047 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
3049 /* we assume we are in a native (no replacement point)! */
3050 ss = replace_recover_source_state(NULL, sfi, es);
3052 /* map the sourcestate using the identity mapping */
3053 replace_map_source_state_identity(ss);
3055 /* remember executionstate and sourcestate for this thread */
3056 GC_EXECUTIONSTATE = es;
3057 GC_SOURCESTATE = ss;
3062 /******************************************************************************/
3063 /* NOTE: No important code below. */
3064 /******************************************************************************/
3067 /* statistics *****************************************************************/
3069 #if defined(REPLACE_STATISTICS)
3070 static void print_freq(FILE *file,int *array,int limit)
3075 for (i=0; i<limit; ++i)
3077 sum += array[limit];
3078 for (i=0; i<limit; ++i) {
3080 fprintf(file," %3d: %8d (cum %3d%%)\n",
3081 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3083 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3085 #endif /* defined(REPLACE_STATISTICS) */
3088 #if defined(REPLACE_STATISTICS)
3090 #define REPLACE_PRINT_DIST(name, array) \
3091 printf(" " name " distribution:\n"); \
3092 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3094 void replace_print_statistics(void)
3096 printf("replacement statistics:\n");
3097 printf(" # of replacements: %d\n", stat_replacements);
3098 printf(" # of frames: %d\n", stat_frames);
3099 printf(" # of recompilations: %d\n", stat_recompile);
3100 printf(" patched static calls:%d\n", stat_staticpatch);
3101 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3102 printf(" unrolled calls: %d\n", stat_unroll_call);
3103 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3104 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3105 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3106 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3107 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3108 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3109 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3110 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3111 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3112 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3114 printf(" # of methods: %d\n", stat_methods);
3115 printf(" # of replacement points: %d\n", stat_rploints);
3116 printf(" # of regallocs: %d\n", stat_regallocs);
3117 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3118 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3119 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3123 #endif /* defined(REPLACE_STATISTICS) */
3126 #if defined(REPLACE_STATISTICS)
3127 static void replace_statistics_source_frame(sourceframe_t *frame)
3136 for (i=0; i<frame->javalocalcount; ++i) {
3137 switch (frame->javalocaltype[i]) {
3138 case TYPE_ADR: adr++; break;
3139 case TYPE_RET: ret++; break;
3140 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3141 case TYPE_VOID: vd++; break;
3146 REPLACE_COUNT_DIST(stat_dist_locals, n);
3147 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3148 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3149 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3150 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3151 adr = ret = prim = n = 0;
3152 for (i=0; i<frame->javastackdepth; ++i) {
3153 switch (frame->javastacktype[i]) {
3154 case TYPE_ADR: adr++; break;
3155 case TYPE_RET: ret++; break;
3156 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3160 REPLACE_COUNT_DIST(stat_dist_stack, n);
3161 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3162 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3163 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3165 #endif /* defined(REPLACE_STATISTICS) */
3168 /* debugging helpers **********************************************************/
3170 /* replace_replacement_point_println *******************************************
3172 Print replacement point info.
3175 rp...............the replacement point to print
3177 *******************************************************************************/
3179 #if !defined(NDEBUG)
3181 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3183 static char *replace_type_str[] = {
3193 void replace_replacement_point_println(rplpoint *rp, int depth)
3199 printf("(rplpoint *)NULL\n");
3203 for (j=0; j<depth; ++j)
3206 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3207 rp->id, (void*)rp,rp->pc,rp->callsize,
3208 replace_type_str[rp->type]);
3209 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3211 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3212 printf(" COUNTDOWN");
3213 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3215 printf(" parent:%p\n", (void*)rp->parent);
3216 for (j=0; j<depth; ++j)
3218 printf("ra:%d = [", rp->regalloccount);
3220 for (j=0; j<rp->regalloccount; ++j) {
3223 index = rp->regalloc[j].index;
3225 case RPLALLOC_STACK: printf("S"); break;
3226 case RPLALLOC_PARAM: printf("P"); break;
3227 case RPLALLOC_SYNC : printf("Y"); break;
3228 default: printf("%d", index);
3230 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3231 if (rp->regalloc[j].type == TYPE_RET) {
3232 printf("ret(L%03d)", rp->regalloc[j].regoff);
3235 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3240 for (j=0; j<depth; ++j)
3243 method_print(rp->method);
3247 #endif /* !defined(NDEBUG) */
3250 /* replace_show_replacement_points *********************************************
3252 Print replacement point info.
3255 code.............codeinfo whose replacement points should be printed.
3257 *******************************************************************************/
3259 #if !defined(NDEBUG)
3260 void replace_show_replacement_points(codeinfo *code)
3268 printf("(codeinfo *)NULL\n");
3272 printf("\treplacement points: %d\n",code->rplpointcount);
3274 printf("\ttotal allocations : %d\n",code->regalloccount);
3275 printf("\tsaved int regs : %d\n",code->savedintcount);
3276 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3277 #if defined(HAS_ADDRESS_REGISTER_FILE)
3278 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3280 printf("\tmemuse : %d\n",code->memuse);
3284 for (i=0; i<code->rplpointcount; ++i) {
3285 rp = code->rplpoints + i;
3288 parent = rp->parent;
3291 parent = parent->parent;
3293 replace_replacement_point_println(rp, depth);
3299 /* replace_executionstate_println **********************************************
3301 Print execution state
3304 es...............the execution state to print
3306 *******************************************************************************/
3308 #if !defined(NDEBUG)
3309 void replace_executionstate_println(executionstate_t *es)
3317 printf("(executionstate_t *)NULL\n");
3321 printf("executionstate_t:\n");
3322 printf("\tpc = %p",(void*)es->pc);
3323 printf(" sp = %p",(void*)es->sp);
3324 printf(" pv = %p\n",(void*)es->pv);
3325 #if defined(ENABLE_DISASSEMBLER)
3326 for (i=0; i<INT_REG_CNT; ++i) {
3331 #if SIZEOF_VOID_P == 8
3332 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3334 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3339 for (i=0; i<FLT_REG_CNT; ++i) {
3344 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3348 # if defined(HAS_ADDRESS_REGISTER_FILE)
3349 for (i=0; i<ADR_REG_CNT; ++i) {
3354 printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
3361 sp = (stackslot_t *) es->sp;
3366 methoddesc *md = es->code->m->parseddesc;
3367 slots = es->code->stackframesize;
3368 extraslots = 1 + md->memuse;
3375 printf("\tstack slots(+%d) at sp:", extraslots);
3376 for (i=0; i<slots+extraslots; ++i) {
3379 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3380 #ifdef HAS_4BYTE_STACKSLOT
3381 printf("%08lx",(unsigned long)*sp++);
3383 printf("%016llx",(unsigned long long)*sp++);
3385 printf("%c", (i >= slots) ? ')' : ' ');
3390 printf("\tcode: %p", (void*)es->code);
3391 if (es->code != NULL) {
3392 printf(" stackframesize=%d ", es->code->stackframesize);
3393 method_print(es->code->m);
3401 #if !defined(NDEBUG)
3402 static void java_value_print(s4 type, replace_val_t value)
3407 printf("%016llx",(unsigned long long) value.l);
3409 if (type < 0 || type > TYPE_RET)
3410 printf(" <INVALID TYPE:%d>", type);
3412 printf(" %s", show_jit_type_names[type]);
3414 if (type == TYPE_ADR && value.a != NULL) {
3417 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3419 if (obj->vftbl->class == class_java_lang_String) {
3421 u = javastring_toutf(obj, false);
3422 utf_display_printable_ascii(u);
3426 else if (type == TYPE_INT) {
3427 printf(" %ld", (long) value.i);
3429 else if (type == TYPE_LNG) {
3430 printf(" %lld", (long long) value.l);
3432 else if (type == TYPE_FLT) {
3433 printf(" %f", value.f);
3435 else if (type == TYPE_DBL) {
3436 printf(" %f", value.d);
3439 #endif /* !defined(NDEBUG) */
3442 #if !defined(NDEBUG)
3443 void replace_source_frame_println(sourceframe_t *frame)
3448 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3449 printf("\tNATIVE\n");
3450 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3451 printf("\tnativepc: %p\n", frame->nativepc);
3452 printf("\tframesize: %d\n", frame->nativeframesize);
3455 for (i=0; i<INT_REG_CNT; ++i) {
3456 if (nregdescint[i] == REG_SAV)
3457 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3461 for (i=0; i<FLT_REG_CNT; ++i) {
3462 if (nregdescfloat[i] == REG_SAV)
3463 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3471 method_println(frame->method);
3472 printf("\tid: %d\n", frame->id);
3473 printf("\ttype: %s\n", replace_type_str[frame->type]);
3476 if (frame->instance.a) {
3477 printf("\tinstance: ");
3478 java_value_print(TYPE_ADR, frame->instance);
3482 if (frame->javalocalcount) {
3483 printf("\tlocals (%d):\n",frame->javalocalcount);
3484 for (i=0; i<frame->javalocalcount; ++i) {
3485 t = frame->javalocaltype[i];
3486 if (t == TYPE_VOID) {
3487 printf("\tlocal[ %2d] = void\n",i);
3490 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3491 java_value_print(t, frame->javalocals[i]);
3498 if (frame->javastackdepth) {
3499 printf("\tstack (depth %d):\n",frame->javastackdepth);
3500 for (i=0; i<frame->javastackdepth; ++i) {
3501 t = frame->javastacktype[i];
3502 if (t == TYPE_VOID) {
3503 printf("\tstack[%2d] = void", i);
3506 printf("\tstack[%2d] = ",i);
3507 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3514 if (frame->syncslotcount) {
3515 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3516 for (i=0; i<frame->syncslotcount; ++i) {
3517 printf("\tslot[%2d] = ",i);
3518 #ifdef HAS_4BYTE_STACKSLOT
3519 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3521 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3527 if (frame->fromcode) {
3528 printf("\tfrom %p ", (void*)frame->fromcode);
3529 method_println(frame->fromcode->m);
3531 if (frame->tocode) {
3532 printf("\tto %p ", (void*)frame->tocode);
3533 method_println(frame->tocode->m);
3536 if (frame->fromrp) {
3537 printf("\tfrom replacement point:\n");
3538 replace_replacement_point_println(frame->fromrp, 2);
3541 printf("\tto replacement point:\n");
3542 replace_replacement_point_println(frame->torp, 2);
3547 #endif /* !defined(NDEBUG) */
3550 /* replace_sourcestate_println *************************************************
3555 ss...............the source state to print
3557 *******************************************************************************/
3559 #if !defined(NDEBUG)
3560 void replace_sourcestate_println(sourcestate_t *ss)
3563 sourceframe_t *frame;
3566 printf("(sourcestate_t *)NULL\n");
3570 printf("sourcestate_t:\n");
3572 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3573 printf(" frame %d:\n", i);
3574 replace_source_frame_println(frame);
3580 /* replace_sourcestate_println_short *******************************************
3582 Print a compact representation of the given source state.
3585 ss...............the source state to print
3587 *******************************************************************************/
3589 #if !defined(NDEBUG)
3590 void replace_sourcestate_println_short(sourcestate_t *ss)
3592 sourceframe_t *frame;
3594 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3597 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3598 printf("NATIVE (pc %p size %d) ",
3599 (void*)frame->nativepc, frame->nativeframesize);
3600 replace_stackframeinfo_println(frame->sfi);
3605 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3608 printf("%s", replace_type_str[frame->fromrp->type]);
3610 if (frame->torp && frame->torp->type != frame->fromrp->type)
3611 printf("->%s", replace_type_str[frame->torp->type]);
3613 if (frame->tocode != frame->fromcode)
3614 printf(" (%p->%p/%d) ",
3615 (void*) frame->fromcode, (void*) frame->tocode,
3618 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3620 method_println(frame->method);
3625 #if !defined(NDEBUG)
3626 static void replace_stackframeinfo_println(stackframeinfo *sfi)
3628 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3629 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3630 (void*)sfi->ra, (void*)sfi->xpc);
3633 method_println(sfi->method);
3640 * These are local overrides for various environment variables in Emacs.
3641 * Please do not remove this and leave it at the end of the file, where
3642 * Emacs will automagically detect them.
3643 * ---------------------------------------------------------------------
3646 * indent-tabs-mode: t
3650 * vim:noexpandtab:sw=4:ts=4: