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)
810 assert(code->savedmcode == NULL);
812 /* count trappable replacement points */
815 i = code->rplpointcount;
816 rp = code->rplpoints;
818 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
821 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
827 /* allocate buffer for saved machine code */
829 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
830 code->savedmcode = savedmcode;
831 savedmcode += count * REPLACEMENT_PATCH_SIZE;
833 /* activate trappable replacement points */
834 /* (in reverse order to handle overlapping points within basic blocks) */
836 i = code->rplpointcount;
837 rp = code->rplpoints + i;
839 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
841 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
844 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
847 DOLOG( printf("activate replacement point:\n");
848 replace_replacement_point_println(rp, 1); fflush(stdout); );
850 savedmcode -= REPLACEMENT_PATCH_SIZE;
852 #if defined(ENABLE_JIT)
853 md_patch_replacement_point(rp->pc, savedmcode, false);
856 rp->flags |= RPLPOINT_FLAG_ACTIVE;
859 assert(savedmcode == code->savedmcode);
863 /* replace_deactivate_replacement_points ***************************************
865 Deactivate a replacement points in the given compilation unit.
866 When this function returns, the replacement points will be "un-armed",
867 that is a each thread reaching a point will just continue normally.
870 code.............the compilation unit
872 *******************************************************************************/
874 void replace_deactivate_replacement_points(codeinfo *code)
881 if (code->savedmcode == NULL) {
882 /* disarm countdown points by patching the branches */
884 i = code->rplpointcount;
885 rp = code->rplpoints;
887 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
888 == RPLPOINT_FLAG_COUNTDOWN)
891 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
898 assert(code->savedmcode != NULL);
899 savedmcode = code->savedmcode;
901 /* de-activate each trappable replacement point */
903 i = code->rplpointcount;
904 rp = code->rplpoints;
907 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
912 DOLOG( printf("deactivate replacement point:\n");
913 replace_replacement_point_println(rp, 1); fflush(stdout); );
915 #if defined(ENABLE_JIT)
916 md_patch_replacement_point(rp->pc, savedmcode, true);
919 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
921 savedmcode += REPLACEMENT_PATCH_SIZE;
924 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
926 /* free saved machine code */
928 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
929 code->savedmcode = NULL;
933 /******************************************************************************/
934 /* PART III: The replacement mechanism */
935 /******************************************************************************/
938 /* replace_read_value **********************************************************
940 Read a value with the given allocation from the execution state.
943 es...............execution state
944 ra...............allocation
945 javaval..........where to put the value
948 *javaval.........the value
950 *******************************************************************************/
952 static void replace_read_value(executionstate_t *es,
954 replace_val_t *javaval)
956 if (ra->flags & INMEMORY) {
957 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
958 #ifdef HAS_4BYTE_STACKSLOT
959 if (IS_2_WORD_TYPE(ra->type)) {
960 javaval->l = *(u8*)(es->sp + ra->regoff);
964 javaval->p = *(ptrint*)(es->sp + ra->regoff);
965 #ifdef HAS_4BYTE_STACKSLOT
970 /* allocated register */
971 if (IS_FLT_DBL_TYPE(ra->type)) {
972 javaval->d = es->fltregs[ra->regoff];
974 if (ra->type == TYPE_FLT)
975 javaval->f = javaval->d;
977 #if defined(HAS_ADDRESS_REGISTER_FILE)
978 else if (IS_ADR_TYPE(ra->type)) {
979 javaval->p = es->adrregs[ra->regoff];
983 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
984 if (ra->type == TYPE_LNG) {
985 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
986 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
989 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
990 javaval->p = es->intregs[ra->regoff];
996 /* replace_write_value *********************************************************
998 Write a value to the given allocation in the execution state.
1001 es...............execution state
1002 ra...............allocation
1003 *javaval.........the value
1005 *******************************************************************************/
1007 static void replace_write_value(executionstate_t *es,
1009 replace_val_t *javaval)
1011 if (ra->flags & INMEMORY) {
1012 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1013 #ifdef HAS_4BYTE_STACKSLOT
1014 if (IS_2_WORD_TYPE(ra->type)) {
1015 *(u8*)(es->sp + ra->regoff) = javaval->l;
1019 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1020 #ifdef HAS_4BYTE_STACKSLOT
1025 /* allocated register */
1028 es->fltregs[ra->regoff] = (double) javaval->f;
1031 es->fltregs[ra->regoff] = javaval->d;
1033 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1035 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1036 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1039 #if defined(HAS_ADDRESS_REGISTER_FILE)
1041 es->adrregs[ra->regoff] = javaval->p;
1044 es->intregs[ra->regoff] = javaval->p;
1050 /* replace_new_sourceframe *****************************************************
1052 Allocate a new source frame and insert it at the front of the frame list.
1055 ss...............the source state
1058 ss->frames.......set to new frame (the new head of the frame list).
1061 returns the new frame
1063 *******************************************************************************/
1065 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1067 sourceframe_t *frame;
1069 frame = DNEW(sourceframe_t);
1070 MZERO(frame, sourceframe_t, 1);
1072 frame->down = ss->frames;
1079 /* replace_read_executionstate *************************************************
1081 Read a source frame from the given executions state.
1082 The new source frame is pushed to the front of the frame list of the
1086 rp...............replacement point at which `es` was taken
1087 es...............execution state
1088 ss...............the source state to add the source frame to
1089 topframe.........true, if the first (top-most) source frame on the
1093 *ss..............the source state with the newly created source frame
1096 *******************************************************************************/
1098 static s4 replace_normalize_type_map[] = {
1099 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1100 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1101 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1102 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1103 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1104 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1105 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1109 static void replace_read_executionstate(rplpoint *rp,
1110 executionstate_t *es,
1119 sourceframe_t *frame;
1122 stackslot_t *basesp;
1124 code = code_find_codeinfo_for_pc(rp->pc);
1126 topslot = TOP_IS_NORMAL;
1130 sp = (stackslot_t *) es->sp;
1132 /* in some cases the top stack slot is passed in REG_ITMP1 */
1134 if (rp->type == BBTYPE_EXH) {
1135 topslot = TOP_IS_IN_ITMP1;
1138 /* calculate base stack pointer */
1140 basesp = sp + code->stackframesize;
1142 /* create the source frame */
1144 frame = replace_new_sourceframe(ss);
1145 frame->method = rp->method;
1147 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1148 frame->type = replace_normalize_type_map[rp->type];
1150 frame->fromcode = code;
1152 /* read local variables */
1154 count = m->maxlocals;
1155 frame->javalocalcount = count;
1156 frame->javalocals = DMNEW(replace_val_t, count);
1157 frame->javalocaltype = DMNEW(u1, count);
1159 /* mark values as undefined */
1160 for (i=0; i<count; ++i) {
1161 #if !defined(NDEBUG)
1162 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1164 frame->javalocaltype[i] = TYPE_VOID;
1167 /* some entries in the intregs array are not meaningful */
1168 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1169 #if !defined(NDEBUG)
1170 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1172 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1174 #endif /* !defined(NDEBUG) */
1176 /* read javalocals */
1178 count = rp->regalloccount;
1181 while (count && (i = ra->index) >= 0) {
1182 assert(i < m->maxlocals);
1183 frame->javalocaltype[i] = ra->type;
1184 if (ra->type == TYPE_RET)
1185 frame->javalocals[i].i = ra->regoff;
1187 replace_read_value(es, ra, frame->javalocals + i);
1192 /* read instance, if this is the first rplpoint */
1194 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1195 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1197 /* we are at the start of the method body, so if local 0 is set, */
1198 /* it is the instance. */
1199 if (frame->javalocaltype[0] == TYPE_ADR)
1200 frame->instance = frame->javalocals[0];
1205 md = rp->method->parseddesc;
1207 assert(md->paramcount >= 1);
1208 instra.type = TYPE_ADR;
1209 instra.regoff = md->params[0].regoff;
1210 if (md->params[0].inmemory) {
1211 instra.flags = INMEMORY;
1212 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1217 replace_read_value(es, &instra, &(frame->instance));
1220 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1222 /* read stack slots */
1224 frame->javastackdepth = count;
1225 frame->javastack = DMNEW(replace_val_t, count);
1226 frame->javastacktype = DMNEW(u1, count);
1228 #if !defined(NDEBUG)
1229 /* mark values as undefined */
1230 for (i=0; i<count; ++i) {
1231 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1232 frame->javastacktype[i] = TYPE_VOID;
1234 #endif /* !defined(NDEBUG) */
1238 /* the first stack slot is special in SBR and EXH blocks */
1240 if (topslot == TOP_IS_ON_STACK) {
1243 assert(ra->index == RPLALLOC_STACK);
1244 assert(ra->type == TYPE_ADR);
1245 frame->javastack[i].p = sp[-1];
1246 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1251 else if (topslot == TOP_IS_IN_ITMP1) {
1254 assert(ra->index == RPLALLOC_STACK);
1255 assert(ra->type == TYPE_ADR);
1256 frame->javastack[i].p = es->intregs[REG_ITMP1];
1257 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1262 else if (topslot == TOP_IS_VOID) {
1265 assert(ra->index == RPLALLOC_STACK);
1266 frame->javastack[i].l = 0;
1267 frame->javastacktype[i] = TYPE_VOID;
1273 /* read remaining stack slots */
1275 for (; count--; ra++) {
1276 if (ra->index == RPLALLOC_SYNC) {
1277 assert(rp->type == RPLPOINT_TYPE_INLINE);
1279 /* only read synchronization slots when traversing an inline point */
1282 sourceframe_t *calleeframe = frame->down;
1283 assert(calleeframe);
1284 assert(calleeframe->syncslotcount == 0);
1285 assert(calleeframe->syncslots == NULL);
1287 calleeframe->syncslotcount = 1;
1288 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1289 replace_read_value(es,ra,calleeframe->syncslots);
1292 frame->javastackdepth--;
1296 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1298 /* do not read parameters of calls down the call chain */
1300 if (!topframe && ra->index == RPLALLOC_PARAM) {
1301 frame->javastackdepth--;
1304 if (ra->type == TYPE_RET)
1305 frame->javastack[i].i = ra->regoff;
1307 replace_read_value(es,ra,frame->javastack + i);
1308 frame->javastacktype[i] = ra->type;
1315 /* replace_write_executionstate ************************************************
1317 Pop a source frame from the front of the frame list of the given source state
1318 and write its values into the execution state.
1321 rp...............replacement point for which execution state should be
1323 es...............the execution state to modify
1324 ss...............the given source state
1325 topframe.........true, if this is the last (top-most) source frame to be
1329 *es..............the execution state derived from the source state
1331 *******************************************************************************/
1333 static void replace_write_executionstate(rplpoint *rp,
1334 executionstate_t *es,
1343 sourceframe_t *frame;
1346 stackslot_t *basesp;
1348 code = code_find_codeinfo_for_pc(rp->pc);
1350 topslot = TOP_IS_NORMAL;
1352 /* pop a source frame */
1356 ss->frames = frame->down;
1358 /* calculate stack pointer */
1360 sp = (stackslot_t *) es->sp;
1362 basesp = sp + code->stackframesize;
1364 /* in some cases the top stack slot is passed in REG_ITMP1 */
1366 if (rp->type == BBTYPE_EXH) {
1367 topslot = TOP_IS_IN_ITMP1;
1370 /* write javalocals */
1373 count = rp->regalloccount;
1375 while (count && (i = ra->index) >= 0) {
1376 assert(i < m->maxlocals);
1377 assert(i < frame->javalocalcount);
1378 assert(ra->type == frame->javalocaltype[i]);
1379 if (ra->type == TYPE_RET) {
1380 /* XXX assert that it matches this rplpoint */
1383 replace_write_value(es, ra, frame->javalocals + i);
1388 /* write stack slots */
1392 /* the first stack slot is special in SBR and EXH blocks */
1394 if (topslot == TOP_IS_ON_STACK) {
1397 assert(ra->index == RPLALLOC_STACK);
1398 assert(i < frame->javastackdepth);
1399 assert(frame->javastacktype[i] == TYPE_ADR);
1400 sp[-1] = frame->javastack[i].p;
1405 else if (topslot == TOP_IS_IN_ITMP1) {
1408 assert(ra->index == RPLALLOC_STACK);
1409 assert(i < frame->javastackdepth);
1410 assert(frame->javastacktype[i] == TYPE_ADR);
1411 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1416 else if (topslot == TOP_IS_VOID) {
1419 assert(ra->index == RPLALLOC_STACK);
1420 assert(i < frame->javastackdepth);
1421 assert(frame->javastacktype[i] == TYPE_VOID);
1427 /* write remaining stack slots */
1429 for (; count--; ra++) {
1430 if (ra->index == RPLALLOC_SYNC) {
1431 assert(rp->type == RPLPOINT_TYPE_INLINE);
1433 /* only write synchronization slots when traversing an inline point */
1436 assert(frame->down);
1437 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1438 assert(frame->down->syncslots != NULL);
1440 replace_write_value(es,ra,frame->down->syncslots);
1445 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1447 /* do not write parameters of calls down the call chain */
1449 if (!topframe && ra->index == RPLALLOC_PARAM) {
1453 assert(i < frame->javastackdepth);
1454 assert(ra->type == frame->javastacktype[i]);
1455 if (ra->type == TYPE_RET) {
1456 /* XXX assert that it matches this rplpoint */
1459 replace_write_value(es,ra,frame->javastack + i);
1471 /* replace_pop_activation_record ***********************************************
1473 Peel a stack frame from the execution state.
1475 *** This function imitates the effects of the method epilog ***
1476 *** and returning from the method call. ***
1479 es...............execution state
1480 frame............source frame, receives synchronization slots
1483 *es..............the execution state after popping the stack frame
1485 *******************************************************************************/
1487 u1* replace_pop_activation_record(executionstate_t *es,
1488 sourceframe_t *frame)
1496 stackslot_t *basesp;
1502 /* read the return address */
1504 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1505 if (CODE_IS_LEAFMETHOD(es->code))
1506 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1509 ra = md_stacktrace_get_returnaddress(es->sp,
1510 SIZE_OF_STACKSLOT * es->code->stackframesize);
1512 DOLOG( printf("return address: %p\n", (void*)ra); );
1516 /* calculate the base of the stack frame */
1518 sp = (stackslot_t *) es->sp;
1519 basesp = sp + es->code->stackframesize;
1521 /* read slots used for synchronization */
1523 assert(frame->syncslotcount == 0);
1524 assert(frame->syncslots == NULL);
1525 count = code_get_sync_slot_count(es->code);
1526 frame->syncslotcount = count;
1527 frame->syncslots = DMNEW(replace_val_t, count);
1528 for (i=0; i<count; ++i) {
1529 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1532 /* restore return address, if part of frame */
1534 #if defined(REPLACE_RA_TOP_OF_FRAME)
1535 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1536 if (!CODE_IS_LEAFMETHOD(es->code))
1538 es->intregs[REPLACE_REG_RA] = *--basesp;
1539 #endif /* REPLACE_RA_TOP_OF_FRAME */
1541 #if defined(REPLACE_RA_LINKAGE_AREA)
1542 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1543 if (!CODE_IS_LEAFMETHOD(es->code))
1545 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1546 #endif /* REPLACE_RA_LINKAGE_AREA */
1548 /* restore saved int registers */
1551 for (i=0; i<es->code->savedintcount; ++i) {
1552 while (nregdescint[--reg] != REG_SAV)
1554 es->intregs[reg] = *--basesp;
1557 /* restore saved flt registers */
1561 for (i=0; i<es->code->savedfltcount; ++i) {
1562 while (nregdescfloat[--reg] != REG_SAV)
1564 basesp -= STACK_SLOTS_PER_FLOAT;
1565 es->fltregs[reg] = *(double*)basesp;
1568 #if defined(HAS_ADDRESS_REGISTER_FILE)
1569 /* restore saved adr registers */
1572 for (i=0; i<es->code->savedadrcount; ++i) {
1573 while (nregdescadr[--reg] != REG_SAV)
1575 es->adrregs[reg] = *--basesp;
1579 /* adjust the stackpointer */
1581 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1583 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1584 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1587 /* Set the new pc. Subtract one so we do not hit the replacement point */
1588 /* of the instruction following the call, if there is one. */
1592 /* find the new codeinfo */
1594 pv = md_codegen_get_pv_from_pc(ra);
1596 DOLOG( printf("PV = %p\n", (void*) pv); );
1598 if (pv == NULL) /* XXX can this really happen? */
1601 code = *(codeinfo **)(pv + CodeinfoPointer);
1603 DOLOG( printf("CODE = %p\n", (void*) code); );
1605 /* return NULL if we reached native code */
1610 /* in debugging mode clobber non-saved registers */
1612 #if !defined(NDEBUG)
1614 for (i=0; i<INT_REG_CNT; ++i)
1615 if ((nregdescint[i] != REG_SAV)
1617 && (i != REPLACE_REG_RA)
1620 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1621 for (i=0; i<FLT_REG_CNT; ++i)
1622 if (nregdescfloat[i] != REG_SAV)
1623 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1624 # if defined(HAS_ADDRESS_REGISTER_FILE)
1625 for (i=0; i<ADR_REG_CNT; ++i)
1626 if (nregdescadr[i] != REG_SAV)
1627 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1629 #endif /* !defined(NDEBUG) */
1631 return (code) ? ra : NULL;
1635 /* replace_patch_method_pointer ************************************************
1637 Patch a method pointer (may be in code, data segment, vftbl, or interface
1641 mpp..............address of the method pointer to patch
1642 entrypoint.......the new entrypoint of the method
1643 kind.............kind of call to patch, used only for debugging
1645 *******************************************************************************/
1647 static void replace_patch_method_pointer(methodptr *mpp,
1648 methodptr entrypoint,
1651 #if !defined(NDEBUG)
1656 DOLOG( printf("patch method pointer from: %p to %p\n",
1657 (void*) *mpp, (void*)entrypoint); );
1659 #if !defined(NDEBUG)
1660 oldcode = *(codeinfo **)((u1*)(*mpp) + CodeinfoPointer);
1661 newcode = *(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer);
1663 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1664 method_println(oldcode->m);
1665 printf("\t with %p ", (void*) newcode);
1666 method_println(newcode->m); );
1668 assert(oldcode->m == newcode->m);
1671 /* write the new entrypoint */
1673 *mpp = (methodptr) entrypoint;
1677 /* replace_patch_class *********************************************************
1679 Patch a method in the given class.
1682 vftbl............vftbl of the class
1683 m................the method to patch
1684 oldentrypoint....the old entrypoint to replace
1685 entrypoint.......the new entrypoint
1687 *******************************************************************************/
1689 void replace_patch_class(vftbl_t *vftbl,
1698 /* patch the vftbl of the class */
1700 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1704 /* patch the interface tables */
1706 assert(oldentrypoint);
1708 for (i=0; i < vftbl->interfacetablelength; ++i) {
1709 mpp = vftbl->interfacetable[-i];
1710 mppend = mpp + vftbl->interfacevftbllength[i];
1711 for (; mpp != mppend; ++mpp)
1712 if (*mpp == oldentrypoint) {
1713 replace_patch_method_pointer(mpp, entrypoint, "interface");
1719 /* replace_patch_class_hierarchy ***********************************************
1721 Patch a method in all loaded classes.
1724 m................the method to patch
1725 oldentrypoint....the old entrypoint to replace
1726 entrypoint.......the new entrypoint
1728 *******************************************************************************/
1730 struct replace_patch_data_t {
1736 #define CODEINFO_OF_CODE(entrypoint) \
1737 (*(codeinfo **)((u1*)(entrypoint) + CodeinfoPointer))
1739 #define METHOD_OF_CODE(entrypoint) \
1740 (CODEINFO_OF_CODE(entrypoint)->m)
1742 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1744 vftbl_t *vftbl = c->vftbl;
1747 && vftbl->vftbllength > pd->m->vftblindex
1748 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1749 && METHOD_OF_CODE(vftbl->table[pd->m->vftblindex]) == pd->m)
1751 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1755 void replace_patch_class_hierarchy(methodinfo *m,
1759 struct replace_patch_data_t pd;
1762 pd.oldentrypoint = oldentrypoint;
1763 pd.entrypoint = entrypoint;
1765 DOLOG_SHORT( printf("patching class hierarchy: ");
1766 method_println(m); );
1768 classcache_foreach_loaded_class(
1769 (classcache_foreach_functionptr_t) &replace_patch_callback,
1774 /* replace_patch_future_calls **************************************************
1776 Analyse a call site and depending on the kind of call patch the call, the
1777 virtual function table, or the interface table.
1780 ra...............return address pointing after the call site
1781 callerframe......source frame of the caller
1782 calleeframe......source frame of the callee, must have been mapped
1784 *******************************************************************************/
1786 void replace_patch_future_calls(u1 *ra,
1787 sourceframe_t *callerframe,
1788 sourceframe_t *calleeframe)
1791 methodptr entrypoint;
1792 methodptr oldentrypoint;
1795 codeinfo *calleecode;
1796 methodinfo *calleem;
1801 assert(callerframe->down == calleeframe);
1803 /* get the new codeinfo and the method that shall be entered */
1805 calleecode = calleeframe->tocode;
1808 calleem = calleeframe->method;
1809 assert(calleem == calleecode->m);
1811 entrypoint = (methodptr) calleecode->entrypoint;
1813 /* check if we are at an method entry rplpoint at the innermost frame */
1815 atentry = (calleeframe->down == NULL)
1816 && !(calleem->flags & ACC_STATIC)
1817 && (calleeframe->fromrp->id == 0); /* XXX */
1819 /* get the position to patch, in case it was a statically bound call */
1821 sfi.pv = callerframe->fromcode->entrypoint;
1822 patchpos = md_get_method_patch_address(ra, &sfi, NULL);
1824 if (patchpos == NULL) {
1825 /* the call was dispatched dynamically */
1827 /* we can only patch such calls if we are at the entry point */
1832 assert((calleem->flags & ACC_STATIC) == 0);
1834 oldentrypoint = calleeframe->fromcode->entrypoint;
1836 /* we need to know the instance */
1838 if (!calleeframe->instance.a) {
1839 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1840 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1846 obj = calleeframe->instance.a;
1849 assert(vftbl->class->vftbl == vftbl);
1851 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1853 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1856 /* the call was statically bound */
1858 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1863 /* replace_push_activation_record **********************************************
1865 Push a stack frame onto the execution state.
1867 *** This function imitates the effects of a call and the ***
1868 *** method prolog of the callee. ***
1871 es...............execution state
1872 rpcall...........the replacement point at the call site
1873 callerframe......source frame of the caller, or NULL for creating the
1875 calleeframe......source frame of the callee, must have been mapped
1878 *es..............the execution state after pushing the stack frame
1880 *******************************************************************************/
1882 void replace_push_activation_record(executionstate_t *es,
1884 sourceframe_t *callerframe,
1885 sourceframe_t *calleeframe)
1890 stackslot_t *basesp;
1893 codeinfo *calleecode;
1896 assert(!rpcall || callerframe);
1897 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1898 assert(!rpcall || rpcall == callerframe->torp);
1899 assert(calleeframe);
1900 assert(!callerframe || calleeframe == callerframe->down);
1902 /* the compilation unit we are entering */
1904 calleecode = calleeframe->tocode;
1907 /* calculate the return address */
1910 ra = rpcall->pc + rpcall->callsize;
1912 ra = es->pc + 1 /* XXX this is ugly */;
1914 /* write the return address */
1916 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1917 es->sp -= SIZE_OF_STACKSLOT;
1919 *((stackslot_t *)es->sp) = (stackslot_t) ra;
1920 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1922 #if defined(REPLACE_REG_RA)
1923 es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1926 /* we move into a new code unit */
1928 es->code = calleecode;
1930 /* set the new pc XXX not needed? */
1932 es->pc = calleecode->entrypoint;
1934 /* build the stackframe */
1936 DOLOG( printf("building stackframe of %d words at %p\n",
1937 calleecode->stackframesize, (void*)es->sp); );
1939 sp = (stackslot_t *) es->sp;
1942 sp -= calleecode->stackframesize;
1945 /* in debug mode, invalidate stack frame first */
1947 /* XXX may not invalidate linkage area used by native code! */
1948 #if !defined(NDEBUG) && 0
1949 for (i=0; i<(basesp - sp); ++i) {
1950 sp[i] = 0xdeaddeadU;
1954 /* save the return address register */
1956 #if defined(REPLACE_RA_TOP_OF_FRAME)
1957 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1958 if (!CODE_IS_LEAFMETHOD(calleecode))
1960 *--basesp = (ptrint) ra;
1961 #endif /* REPLACE_RA_TOP_OF_FRAME */
1963 #if defined(REPLACE_RA_LINKAGE_AREA)
1964 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1965 if (!CODE_IS_LEAFMETHOD(calleecode))
1967 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1968 #endif /* REPLACE_RA_LINKAGE_AREA */
1970 /* save int registers */
1973 for (i=0; i<calleecode->savedintcount; ++i) {
1974 while (nregdescint[--reg] != REG_SAV)
1976 *--basesp = es->intregs[reg];
1978 /* XXX may not clobber saved regs used by native code! */
1979 #if !defined(NDEBUG) && 0
1980 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1984 /* save flt registers */
1988 for (i=0; i<calleecode->savedfltcount; ++i) {
1989 while (nregdescfloat[--reg] != REG_SAV)
1991 basesp -= STACK_SLOTS_PER_FLOAT;
1992 *(double*)basesp = es->fltregs[reg];
1994 /* XXX may not clobber saved regs used by native code! */
1995 #if !defined(NDEBUG) && 0
1996 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
2000 #if defined(HAS_ADDRESS_REGISTER_FILE)
2001 /* save adr registers */
2004 for (i=0; i<calleecode->savedadrcount; ++i) {
2005 while (nregdescadr[--reg] != REG_SAV)
2007 *--basesp = es->adrregs[reg];
2009 /* XXX may not clobber saved regs used by native code! */
2010 #if !defined(NDEBUG) && 0
2011 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
2016 /* write slots used for synchronization */
2018 count = code_get_sync_slot_count(calleecode);
2019 assert(count == calleeframe->syncslotcount);
2020 for (i=0; i<count; ++i) {
2021 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2026 es->pv = calleecode->entrypoint;
2028 /* redirect future invocations */
2030 if (callerframe && rpcall) {
2031 #if defined(REPLACE_PATCH_ALL)
2032 if (rpcall->type == callerframe->fromrp->type)
2034 if (rpcall == callerframe->fromrp)
2036 replace_patch_future_calls(ra, callerframe, calleeframe);
2041 /* replace_find_replacement_point **********************************************
2043 Find the replacement point in the given code corresponding to the
2044 position given in the source frame.
2047 code.............the codeinfo in which to search the rplpoint
2048 frame............the source frame defining the position to look for
2049 parent...........parent replacement point to match
2052 the replacement point
2054 *******************************************************************************/
2056 rplpoint * replace_find_replacement_point(codeinfo *code,
2057 sourceframe_t *frame,
2070 DOLOG( printf("searching replacement point for:\n");
2071 replace_source_frame_println(frame); );
2075 DOLOG( printf("code = %p\n", (void*)code); );
2077 rp = code->rplpoints;
2078 i = code->rplpointcount;
2080 if (rp->id == frame->id && rp->method == frame->method
2081 && rp->parent == parent
2082 && replace_normalize_type_map[rp->type] == frame->type)
2084 /* check if returnAddresses match */
2085 /* XXX optimize: only do this if JSRs in method */
2086 DOLOG( printf("checking match for:");
2087 replace_replacement_point_println(rp, 1); fflush(stdout); );
2090 for (j = rp->regalloccount; j--; ++ra) {
2091 if (ra->type == TYPE_RET) {
2092 if (ra->index == RPLALLOC_STACK) {
2093 assert(stacki < frame->javastackdepth);
2094 if (frame->javastack[stacki].i != ra->regoff)
2099 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2100 if (frame->javalocals[ra->index].i != ra->regoff)
2113 #if !defined(NDEBUG)
2114 printf("candidate replacement points were:\n");
2115 rp = code->rplpoints;
2116 i = code->rplpointcount;
2118 replace_replacement_point_println(rp, 1);
2122 vm_abort("no matching replacement point found");
2123 return NULL; /* NOT REACHED */
2127 /* replace_find_replacement_point_for_pc ***************************************
2129 Find the nearest replacement point at or before the given PC.
2132 code.............compilation unit the PC is in
2133 pc...............the machine code PC
2136 the replacement point found, or
2137 NULL if no replacement point was found
2139 *******************************************************************************/
2141 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2147 DOLOG( printf("searching for rp in %p ", (void*)code);
2148 method_println(code->m);
2149 printf("PC = %p\n", (void*)pc); );
2153 rp = code->rplpoints;
2154 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2155 DOLOG( replace_replacement_point_println(rp, 2); );
2160 assert(found == NULL || found->pc + found->callsize >= pc);
2166 /* replace_pop_native_frame ****************************************************
2168 Unroll a native frame in the execution state and create a source frame
2172 es...............current execution state
2173 ss...............the current source state
2174 sfi..............stackframeinfo for the native frame
2177 es...............execution state after unrolling the native frame
2178 ss...............gets the added native source frame
2180 *******************************************************************************/
2182 static void replace_pop_native_frame(executionstate_t *es,
2184 stackframeinfo *sfi)
2186 sourceframe_t *frame;
2192 frame = replace_new_sourceframe(ss);
2196 /* remember pc and size of native frame */
2198 frame->nativepc = es->pc;
2199 frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2200 assert(frame->nativeframesize >= 0);
2202 /* remember values of saved registers */
2205 for (i=0; i<INT_REG_CNT; ++i) {
2206 if (nregdescint[i] == REG_SAV)
2207 frame->nativesavint[j++] = es->intregs[i];
2211 for (i=0; i<FLT_REG_CNT; ++i) {
2212 if (nregdescfloat[i] == REG_SAV)
2213 frame->nativesavflt[j++] = es->fltregs[i];
2216 #if defined(HAS_ADDRESS_REGISTER_FILE)
2218 for (i=0; i<ADR_REG_CNT; ++i) {
2219 if (nregdescadr[i] == REG_SAV)
2220 frame->nativesavadr[j++] = es->adrregs[i];
2224 /* restore saved registers */
2226 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2228 for (i=0; i<INT_REG_CNT; ++i) {
2229 if (nregdescint[i] == REG_SAV)
2230 es->intregs[i] = sfi->intregs[j++];
2233 /* XXX we don't have them, yet, in the sfi, so clear them */
2235 for (i=0; i<INT_REG_CNT; ++i) {
2236 if (nregdescint[i] == REG_SAV)
2241 /* XXX we don't have float registers in the sfi, so clear them */
2243 for (i=0; i<FLT_REG_CNT; ++i) {
2244 if (nregdescfloat[i] == REG_SAV)
2245 es->fltregs[i] = 0.0;
2248 #if defined(HAS_ADDRESS_REGISTER_FILE)
2249 # if defined(ENABLE_GC_CACAO)
2251 for (i=0; i<ADR_REG_CNT; ++i) {
2252 if (nregdescadr[i] == REG_SAV)
2253 es->adrregs[i] = sfi->adrregs[j++];
2256 for (i=0; i<ADR_REG_CNT; ++i) {
2257 if (nregdescadr[i] == REG_SAV)
2263 /* restore pv, pc, and sp */
2265 if (sfi->pv == NULL) {
2266 /* frame of a native function call */
2267 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2272 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2275 /* find the new codeinfo */
2277 DOLOG( printf("PV = %p\n", (void*) es->pv); );
2279 assert(es->pv != NULL);
2281 code = *(codeinfo **)(es->pv + CodeinfoPointer);
2283 DOLOG( printf("CODE = %p\n", (void*) code); );
2289 /* replace_push_native_frame ***************************************************
2291 Rebuild a native frame onto the execution state and remove its source frame.
2293 Note: The native frame is "rebuild" by setting fields like PC and stack
2294 pointer in the execution state accordingly. Values in the
2295 stackframeinfo may be modified, but the actual stack frame of the
2296 native code is not touched.
2299 es...............current execution state
2300 ss...............the current source state
2303 es...............execution state after re-rolling the native frame
2304 ss...............the native source frame is removed
2306 *******************************************************************************/
2308 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2310 sourceframe_t *frame;
2316 DOLOG( printf("pushing native frame\n"); );
2318 /* remove the frame from the source state */
2322 assert(REPLACE_IS_NATIVE_FRAME(frame));
2324 ss->frames = frame->down;
2326 /* assert that the native frame has not moved */
2328 assert(es->sp == frame->sfi->sp);
2330 /* update saved registers in the stackframeinfo */
2332 #if defined(ENABLE_GC_CACAO)
2334 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2335 for (i=0; i<INT_REG_CNT; ++i) {
2336 if (nregdescint[i] == REG_SAV)
2337 frame->sfi->intregs[j++] = es->intregs[i];
2340 for (i=0; i<ADR_REG_CNT; ++i) {
2341 if (nregdescadr[i] == REG_SAV)
2342 frame->sfi->adrregs[j++] = es->adrregs[i];
2346 /* XXX leave float registers untouched here */
2349 /* restore saved registers */
2352 for (i=0; i<INT_REG_CNT; ++i) {
2353 if (nregdescint[i] == REG_SAV)
2354 es->intregs[i] = frame->nativesavint[j++];
2358 for (i=0; i<FLT_REG_CNT; ++i) {
2359 if (nregdescfloat[i] == REG_SAV)
2360 es->fltregs[i] = frame->nativesavflt[j++];
2363 #if defined(HAS_ADDRESS_REGISTER_FILE)
2365 for (i=0; i<ADR_REG_CNT; ++i) {
2366 if (nregdescadr[i] == REG_SAV)
2367 es->adrregs[i] = frame->nativesavadr[j++];
2371 /* skip the native frame on the machine stack */
2373 es->sp -= frame->nativeframesize;
2375 /* set the pc the next frame must return to */
2377 es->pc = frame->nativepc;
2381 /* replace_recover_source_state ************************************************
2383 Recover the source state from the given replacement point and execution
2387 rp...............replacement point that has been reached, if any
2388 sfi..............stackframeinfo, if called from native code
2389 es...............execution state at the replacement point rp
2394 *******************************************************************************/
2396 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2397 stackframeinfo *sfi,
2398 executionstate_t *es)
2403 #if defined(REPLACE_STATISTICS)
2407 /* create the source frame structure in dump memory */
2409 ss = DNEW(sourcestate_t);
2412 /* each iteration of the loop recovers one source frame */
2419 DOLOG( replace_executionstate_println(es); );
2421 /* if we are not at a replacement point, it is a native frame */
2424 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2427 replace_pop_native_frame(es, ss, sfi);
2430 if (es->code == NULL)
2433 goto after_machine_frame;
2436 /* read the values for this source frame from the execution state */
2438 DOLOG( printf("recovering source state for%s:\n",
2439 (ss->frames == NULL) ? " TOPFRAME" : "");
2440 replace_replacement_point_println(rp, 1); );
2442 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2444 #if defined(ENABLE_VMLOG)
2445 vmlog_cacao_unrol_method(ss->frames->method);
2448 #if defined(REPLACE_STATISTICS)
2449 REPLACE_COUNT(stat_frames);
2451 replace_statistics_source_frame(ss->frames);
2454 /* in locked areas (below native frames), identity map the frame */
2457 ss->frames->torp = ss->frames->fromrp;
2458 ss->frames->tocode = ss->frames->fromcode;
2461 /* unroll to the next (outer) frame */
2464 /* this frame is in inlined code */
2466 DOLOG( printf("INLINED!\n"); );
2470 assert(rp->type == RPLPOINT_TYPE_INLINE);
2471 REPLACE_COUNT(stat_unroll_inline);
2474 /* this frame had been called at machine-level. pop it. */
2476 DOLOG( printf("UNWIND\n"); );
2478 ra = replace_pop_activation_record(es, ss->frames);
2480 DOLOG( printf("REACHED NATIVE CODE\n"); );
2484 #if !defined(ENABLE_GC_CACAO)
2485 break; /* XXX remove to activate native frames */
2490 /* find the replacement point at the call site */
2492 after_machine_frame:
2493 rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2496 vm_abort("could not find replacement point while unrolling call");
2498 DOLOG( printf("found replacement point.\n");
2499 replace_replacement_point_println(rp, 1); );
2501 assert(rp->type == RPLPOINT_TYPE_CALL);
2502 REPLACE_COUNT(stat_unroll_call);
2504 } /* end loop over source frames */
2506 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2512 /* replace_map_source_state ****************************************************
2514 Map each source frame in the given source state to a target replacement
2515 point and compilation unit. If no valid code is available for a source
2516 frame, it is (re)compiled.
2519 ss...............the source state
2522 ss...............the source state, modified: The `torp` and `tocode`
2523 fields of each source frame are set.
2526 true.............everything went ok
2527 false............an exception has been thrown
2529 *******************************************************************************/
2531 static bool replace_map_source_state(sourcestate_t *ss)
2533 sourceframe_t *frame;
2536 rplpoint *parent; /* parent of inlined rplpoint */
2537 #if defined(REPLACE_STATISTICS)
2544 /* iterate over the source frames from outermost to innermost */
2546 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2548 /* XXX skip native frames */
2550 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2555 /* map frames which are not already mapped */
2557 if (frame->tocode) {
2558 code = frame->tocode;
2563 assert(frame->torp == NULL);
2565 if (parent == NULL) {
2566 /* find code for this frame */
2568 #if defined(REPLACE_STATISTICS)
2569 oldcode = frame->method->code;
2571 /* request optimization of hot methods and their callers */
2573 if (frame->method->hitcountdown < 0
2574 || (frame->down && frame->down->method->hitcountdown < 0))
2575 jit_request_optimization(frame->method);
2577 code = jit_get_current_code(frame->method);
2580 return false; /* exception */
2582 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2587 /* map this frame */
2589 rp = replace_find_replacement_point(code, frame, parent);
2591 frame->tocode = code;
2595 if (rp->type == RPLPOINT_TYPE_CALL) {
2608 /* replace_map_source_state_identity *******************************************
2610 Map each source frame in the given source state to the same replacement
2611 point and compilation unit it was derived from. This is mainly used for
2615 ss...............the source state
2618 ss...............the source state, modified: The `torp` and `tocode`
2619 fields of each source frame are set.
2621 *******************************************************************************/
2623 #if defined(ENABLE_GC_CACAO)
2624 static void replace_map_source_state_identity(sourcestate_t *ss)
2626 sourceframe_t *frame;
2628 /* iterate over the source frames from outermost to innermost */
2630 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2632 /* skip native frames */
2634 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2638 /* map frames using the identity mapping */
2640 if (frame->tocode) {
2641 assert(frame->tocode == frame->fromcode);
2642 assert(frame->torp == frame->fromrp);
2644 assert(frame->tocode == NULL);
2645 assert(frame->torp == NULL);
2646 frame->tocode = frame->fromcode;
2647 frame->torp = frame->fromrp;
2654 /* replace_build_execution_state ***********************************************
2656 Build an execution state for the given (mapped) source state.
2658 !!! CAUTION: This function rewrites the machine stack !!!
2660 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2663 ss...............the source state. Must have been mapped by
2664 replace_map_source_state before.
2665 es...............the base execution state on which to build
2668 *es..............the new execution state
2670 *******************************************************************************/
2672 static void replace_build_execution_state(sourcestate_t *ss,
2673 executionstate_t *es)
2676 sourceframe_t *prevframe;
2683 while (ss->frames) {
2685 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2686 prevframe = ss->frames;
2687 replace_push_native_frame(es, ss);
2693 if (parent == NULL) {
2694 /* create a machine-level stack frame */
2696 DOLOG( printf("pushing activation record for:\n");
2697 if (rp) replace_replacement_point_println(rp, 1);
2698 else printf("\tfirst frame\n"); );
2700 replace_push_activation_record(es, rp, prevframe, ss->frames);
2702 DOLOG( replace_executionstate_println(es); );
2705 rp = ss->frames->torp;
2708 DOLOG( printf("creating execution state for%s:\n",
2709 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2710 replace_replacement_point_println(ss->frames->fromrp, 1);
2711 replace_replacement_point_println(rp, 1); );
2713 es->code = ss->frames->tocode;
2714 prevframe = ss->frames;
2716 #if defined(ENABLE_VMLOG)
2717 vmlog_cacao_rerol_method(ss->frames->method);
2720 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2722 DOLOG( replace_executionstate_println(es); );
2724 if (rp->type == RPLPOINT_TYPE_CALL) {
2735 /* replace_me ******************************************************************
2737 This function is called by the signal handler when a thread reaches
2738 a replacement point. `replace_me` must map the execution state to the
2739 target replacement point and let execution continue there.
2741 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2744 rp...............replacement point that has been reached
2745 es...............execution state read by signal handler
2747 *******************************************************************************/
2749 static void replace_me(rplpoint *rp, executionstate_t *es)
2751 stackframeinfo *sfi;
2753 sourceframe_t *frame;
2757 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2758 threadobject *thread;
2761 origcode = es->code;
2764 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2765 stat_replacements, (void*)THREADOBJECT,
2767 method_println(es->code->m); );
2769 DOLOG( replace_replacement_point_println(rp, 1); );
2771 REPLACE_COUNT(stat_replacements);
2773 /* mark start of dump memory area */
2775 dumpsize = dump_size();
2777 /* get the stackframeinfo for the current thread */
2779 sfi = STACKFRAMEINFO;
2781 /* recover source state */
2783 ss = replace_recover_source_state(rp, sfi, es);
2785 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2786 /* if there is a collection pending, we assume the replacement point should
2787 suspend this thread */
2791 thread = THREADOBJECT;
2793 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2795 /* map the sourcestate using the identity mapping */
2796 replace_map_source_state_identity(ss);
2798 /* since we enter the same method again, we turn off rps now */
2799 /* XXX michi: can we really do this? what if the rp was active before
2800 we activated it for the gc? */
2801 replace_deactivate_replacement_points(origcode);
2803 /* remember executionstate and sourcestate for this thread */
2804 GC_EXECUTIONSTATE = es;
2805 GC_SOURCESTATE = ss;
2807 /* really suspend this thread now (PC = 0) */
2808 threads_suspend_ack(NULL, NULL);
2810 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2813 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2815 /* map the source state */
2817 if (!replace_map_source_state(ss))
2818 vm_abort("exception during method replacement");
2820 DOLOG( replace_sourcestate_println(ss); );
2822 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2824 #if !defined(NDEBUG)
2825 /* avoid infinite loops by self-replacement, only if not in testing mode */
2827 if (!opt_TestReplacement) {
2830 frame = frame->down;
2832 if (frame->torp == origrp) {
2834 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2836 replace_deactivate_replacement_points(origcode);
2841 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2845 /* build the new execution state */
2847 replace_build_execution_state(ss, es);
2849 #if !defined(NDEBUG)
2850 /* continue execution after patched machine code, if testing mode enabled */
2852 if (opt_TestReplacement)
2853 es->pc += REPLACEMENT_PATCH_SIZE;
2856 /* release dump area */
2858 dump_release(dumpsize);
2862 /* replace_me_wrapper **********************************************************
2864 This function is called by the signal handler. It determines if there
2865 is an active replacement point pending at the given PC and returns
2868 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2871 pc...............the program counter that triggered the replacement.
2872 context..........the context (machine state) to which the
2873 replacement should be applied.
2876 context..........the context after replacement finished.
2879 true.............replacement done, everything went ok
2880 false............no replacement done, context unchanged
2882 *******************************************************************************/
2884 bool replace_me_wrapper(u1 *pc, void *context)
2888 executionstate_t es;
2890 /* search the codeinfo for the given PC */
2892 code = code_find_codeinfo_for_pc(pc);
2895 /* search for a replacement point at the given PC */
2898 rp = replace_find_replacement_point_for_pc(code, pc);
2899 assert(rp == NULL || rp->pc == pc);
2905 for (i=0,rp2=code->rplpoints; i<code->rplpointcount; i++,rp2++) {
2912 /* check if the replacement point is active */
2914 if (rp != NULL && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
2916 /* set codeinfo pointer in execution state */
2920 /* read execution state from current context */
2922 md_replace_executionstate_read(&es, context);
2924 DOLOG( printf("REPLACEMENT READ: ");
2925 replace_executionstate_println(&es); );
2927 /* do the actual replacement */
2929 replace_me(rp, &es);
2931 /* write execution state to current context */
2933 md_replace_executionstate_write(&es, context);
2935 DOLOG( printf("REPLACEMENT WRITE: ");
2936 replace_executionstate_println(&es); );
2938 /* new code is entered after returning */
2940 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2948 /******************************************************************************/
2949 /* NOTE: Stuff specific to the exact GC is below. */
2950 /******************************************************************************/
2952 #if defined(ENABLE_GC_CACAO)
2953 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
2955 stackframeinfo *sfi;
2956 executionstate_t *es;
2959 /* get the stackframeinfo of this thread */
2960 assert(thread == THREADOBJECT);
2961 sfi = STACKFRAMEINFO;
2963 /* create the execution state */
2964 es = DNEW(executionstate_t);
2967 es->pv = 0; /* since we are in a native, PV is invalid! */
2968 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
2970 /* we assume we are in a native (no replacement point)! */
2971 ss = replace_recover_source_state(NULL, sfi, es);
2973 /* map the sourcestate using the identity mapping */
2974 replace_map_source_state_identity(ss);
2976 /* remember executionstate and sourcestate for this thread */
2977 GC_EXECUTIONSTATE = es;
2978 GC_SOURCESTATE = ss;
2983 /******************************************************************************/
2984 /* NOTE: No important code below. */
2985 /******************************************************************************/
2988 /* statistics *****************************************************************/
2990 #if defined(REPLACE_STATISTICS)
2991 static void print_freq(FILE *file,int *array,int limit)
2996 for (i=0; i<limit; ++i)
2998 sum += array[limit];
2999 for (i=0; i<limit; ++i) {
3001 fprintf(file," %3d: %8d (cum %3d%%)\n",
3002 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3004 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3006 #endif /* defined(REPLACE_STATISTICS) */
3009 #if defined(REPLACE_STATISTICS)
3011 #define REPLACE_PRINT_DIST(name, array) \
3012 printf(" " name " distribution:\n"); \
3013 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3015 void replace_print_statistics(void)
3017 printf("replacement statistics:\n");
3018 printf(" # of replacements: %d\n", stat_replacements);
3019 printf(" # of frames: %d\n", stat_frames);
3020 printf(" # of recompilations: %d\n", stat_recompile);
3021 printf(" patched static calls:%d\n", stat_staticpatch);
3022 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3023 printf(" unrolled calls: %d\n", stat_unroll_call);
3024 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3025 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3026 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3027 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3028 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3029 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3030 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3031 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3032 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3033 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3035 printf(" # of methods: %d\n", stat_methods);
3036 printf(" # of replacement points: %d\n", stat_rploints);
3037 printf(" # of regallocs: %d\n", stat_regallocs);
3038 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3039 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3040 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3044 #endif /* defined(REPLACE_STATISTICS) */
3047 #if defined(REPLACE_STATISTICS)
3048 static void replace_statistics_source_frame(sourceframe_t *frame)
3057 for (i=0; i<frame->javalocalcount; ++i) {
3058 switch (frame->javalocaltype[i]) {
3059 case TYPE_ADR: adr++; break;
3060 case TYPE_RET: ret++; break;
3061 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3062 case TYPE_VOID: vd++; break;
3067 REPLACE_COUNT_DIST(stat_dist_locals, n);
3068 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3069 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3070 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3071 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3072 adr = ret = prim = n = 0;
3073 for (i=0; i<frame->javastackdepth; ++i) {
3074 switch (frame->javastacktype[i]) {
3075 case TYPE_ADR: adr++; break;
3076 case TYPE_RET: ret++; break;
3077 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3081 REPLACE_COUNT_DIST(stat_dist_stack, n);
3082 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3083 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3084 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3086 #endif /* defined(REPLACE_STATISTICS) */
3089 /* debugging helpers **********************************************************/
3091 /* replace_replacement_point_println *******************************************
3093 Print replacement point info.
3096 rp...............the replacement point to print
3098 *******************************************************************************/
3100 #if !defined(NDEBUG)
3102 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3104 static char *replace_type_str[] = {
3114 void replace_replacement_point_println(rplpoint *rp, int depth)
3120 printf("(rplpoint *)NULL\n");
3124 for (j=0; j<depth; ++j)
3127 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3128 rp->id, (void*)rp,rp->pc,rp->callsize,
3129 replace_type_str[rp->type]);
3130 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3132 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3133 printf(" COUNTDOWN");
3134 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3136 printf(" parent:%p\n", (void*)rp->parent);
3137 for (j=0; j<depth; ++j)
3139 printf("ra:%d = [", rp->regalloccount);
3141 for (j=0; j<rp->regalloccount; ++j) {
3144 index = rp->regalloc[j].index;
3146 case RPLALLOC_STACK: printf("S"); break;
3147 case RPLALLOC_PARAM: printf("P"); break;
3148 case RPLALLOC_SYNC : printf("Y"); break;
3149 default: printf("%d", index);
3151 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3152 if (rp->regalloc[j].type == TYPE_RET) {
3153 printf("ret(L%03d)", rp->regalloc[j].regoff);
3156 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3161 for (j=0; j<depth; ++j)
3164 method_print(rp->method);
3168 #endif /* !defined(NDEBUG) */
3171 /* replace_show_replacement_points *********************************************
3173 Print replacement point info.
3176 code.............codeinfo whose replacement points should be printed.
3178 *******************************************************************************/
3180 #if !defined(NDEBUG)
3181 void replace_show_replacement_points(codeinfo *code)
3189 printf("(codeinfo *)NULL\n");
3193 printf("\treplacement points: %d\n",code->rplpointcount);
3195 printf("\ttotal allocations : %d\n",code->regalloccount);
3196 printf("\tsaved int regs : %d\n",code->savedintcount);
3197 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3198 #if defined(HAS_ADDRESS_REGISTER_FILE)
3199 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3201 printf("\tmemuse : %d\n",code->memuse);
3205 for (i=0; i<code->rplpointcount; ++i) {
3206 rp = code->rplpoints + i;
3209 parent = rp->parent;
3212 parent = parent->parent;
3214 replace_replacement_point_println(rp, depth);
3220 /* replace_executionstate_println **********************************************
3222 Print execution state
3225 es...............the execution state to print
3227 *******************************************************************************/
3229 #if !defined(NDEBUG)
3230 void replace_executionstate_println(executionstate_t *es)
3238 printf("(executionstate_t *)NULL\n");
3242 printf("executionstate_t:\n");
3243 printf("\tpc = %p",(void*)es->pc);
3244 printf(" sp = %p",(void*)es->sp);
3245 printf(" pv = %p\n",(void*)es->pv);
3246 #if defined(ENABLE_DISASSEMBLER)
3247 for (i=0; i<INT_REG_CNT; ++i) {
3252 #if SIZEOF_VOID_P == 8
3253 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3255 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3260 for (i=0; i<FLT_REG_CNT; ++i) {
3265 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3269 # if defined(HAS_ADDRESS_REGISTER_FILE)
3270 for (i=0; i<ADR_REG_CNT; ++i) {
3275 printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
3282 sp = (stackslot_t *) es->sp;
3287 methoddesc *md = es->code->m->parseddesc;
3288 slots = es->code->stackframesize;
3289 extraslots = 1 + md->memuse;
3296 printf("\tstack slots(+%d) at sp:", extraslots);
3297 for (i=0; i<slots+extraslots; ++i) {
3300 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3301 #ifdef HAS_4BYTE_STACKSLOT
3302 printf("%08lx",(unsigned long)*sp++);
3304 printf("%016llx",(unsigned long long)*sp++);
3306 printf("%c", (i >= slots) ? ')' : ' ');
3311 printf("\tcode: %p", (void*)es->code);
3312 if (es->code != NULL) {
3313 printf(" stackframesize=%d ", es->code->stackframesize);
3314 method_print(es->code->m);
3322 #if !defined(NDEBUG)
3323 static void java_value_print(s4 type, replace_val_t value)
3328 printf("%016llx",(unsigned long long) value.l);
3330 if (type < 0 || type > TYPE_RET)
3331 printf(" <INVALID TYPE:%d>", type);
3333 printf(" %s", show_jit_type_names[type]);
3335 if (type == TYPE_ADR && value.a != NULL) {
3338 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3340 if (obj->vftbl->class == class_java_lang_String) {
3342 u = javastring_toutf(obj, false);
3343 utf_display_printable_ascii(u);
3347 else if (type == TYPE_INT) {
3348 printf(" %ld", (long) value.i);
3350 else if (type == TYPE_LNG) {
3351 printf(" %lld", (long long) value.l);
3353 else if (type == TYPE_FLT) {
3354 printf(" %f", value.f);
3356 else if (type == TYPE_DBL) {
3357 printf(" %f", value.d);
3360 #endif /* !defined(NDEBUG) */
3363 #if !defined(NDEBUG)
3364 void replace_source_frame_println(sourceframe_t *frame)
3369 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3370 printf("\tNATIVE\n");
3371 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3372 printf("\tnativepc: %p\n", frame->nativepc);
3373 printf("\tframesize: %d\n", frame->nativeframesize);
3376 for (i=0; i<INT_REG_CNT; ++i) {
3377 if (nregdescint[i] == REG_SAV)
3378 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3382 for (i=0; i<FLT_REG_CNT; ++i) {
3383 if (nregdescfloat[i] == REG_SAV)
3384 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3392 method_println(frame->method);
3393 printf("\tid: %d\n", frame->id);
3394 printf("\ttype: %s\n", replace_type_str[frame->type]);
3397 if (frame->instance.a) {
3398 printf("\tinstance: ");
3399 java_value_print(TYPE_ADR, frame->instance);
3403 if (frame->javalocalcount) {
3404 printf("\tlocals (%d):\n",frame->javalocalcount);
3405 for (i=0; i<frame->javalocalcount; ++i) {
3406 t = frame->javalocaltype[i];
3407 if (t == TYPE_VOID) {
3408 printf("\tlocal[ %2d] = void\n",i);
3411 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3412 java_value_print(t, frame->javalocals[i]);
3419 if (frame->javastackdepth) {
3420 printf("\tstack (depth %d):\n",frame->javastackdepth);
3421 for (i=0; i<frame->javastackdepth; ++i) {
3422 t = frame->javastacktype[i];
3423 if (t == TYPE_VOID) {
3424 printf("\tstack[%2d] = void", i);
3427 printf("\tstack[%2d] = ",i);
3428 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3435 if (frame->syncslotcount) {
3436 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3437 for (i=0; i<frame->syncslotcount; ++i) {
3438 printf("\tslot[%2d] = ",i);
3439 #ifdef HAS_4BYTE_STACKSLOT
3440 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3442 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3448 if (frame->fromcode) {
3449 printf("\tfrom %p ", (void*)frame->fromcode);
3450 method_println(frame->fromcode->m);
3452 if (frame->tocode) {
3453 printf("\tto %p ", (void*)frame->tocode);
3454 method_println(frame->tocode->m);
3457 if (frame->fromrp) {
3458 printf("\tfrom replacement point:\n");
3459 replace_replacement_point_println(frame->fromrp, 2);
3462 printf("\tto replacement point:\n");
3463 replace_replacement_point_println(frame->torp, 2);
3468 #endif /* !defined(NDEBUG) */
3471 /* replace_sourcestate_println *************************************************
3476 ss...............the source state to print
3478 *******************************************************************************/
3480 #if !defined(NDEBUG)
3481 void replace_sourcestate_println(sourcestate_t *ss)
3484 sourceframe_t *frame;
3487 printf("(sourcestate_t *)NULL\n");
3491 printf("sourcestate_t:\n");
3493 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3494 printf(" frame %d:\n", i);
3495 replace_source_frame_println(frame);
3501 /* replace_sourcestate_println_short *******************************************
3503 Print a compact representation of the given source state.
3506 ss...............the source state to print
3508 *******************************************************************************/
3510 #if !defined(NDEBUG)
3511 void replace_sourcestate_println_short(sourcestate_t *ss)
3513 sourceframe_t *frame;
3515 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3518 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3519 printf("NATIVE (pc %p size %d) ",
3520 (void*)frame->nativepc, frame->nativeframesize);
3521 replace_stackframeinfo_println(frame->sfi);
3526 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3529 printf("%s", replace_type_str[frame->fromrp->type]);
3531 if (frame->torp && frame->torp->type != frame->fromrp->type)
3532 printf("->%s", replace_type_str[frame->torp->type]);
3534 if (frame->tocode != frame->fromcode)
3535 printf(" (%p->%p/%d) ",
3536 (void*) frame->fromcode, (void*) frame->tocode,
3539 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3541 method_println(frame->method);
3546 #if !defined(NDEBUG)
3547 static void replace_stackframeinfo_println(stackframeinfo *sfi)
3549 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3550 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3551 (void*)sfi->ra, (void*)sfi->xpc);
3554 method_println(sfi->method);
3561 * These are local overrides for various environment variables in Emacs.
3562 * Please do not remove this and leave it at the end of the file, where
3563 * Emacs will automagically detect them.
3564 * ---------------------------------------------------------------------
3567 * indent-tabs-mode: t
3571 * vim:noexpandtab:sw=4:ts=4: