1 /* src/vm/jit/replace.cpp - on-stack replacement of methods
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
36 #if defined(ENABLE_GC_CACAO)
37 # include "mm/cacao-gc/gc.h"
40 #include "mm/dumpmemory.hpp"
41 #include "mm/memory.h"
43 #include "threads/thread.hpp"
45 #include "toolbox/logging.h"
47 #include "vm/classcache.hpp"
48 #include "vm/globals.hpp"
49 #include "vm/options.h"
50 #include "vm/string.hpp"
52 #if defined(ENABLE_RT_TIMING)
53 # include "vm/rt-timing.h"
56 #include "vm/jit/abi.h"
57 #include "vm/jit/asmpart.h"
58 #include "vm/jit/disass.h"
59 #include "vm/jit/executionstate.h"
60 #include "vm/jit/jit.hpp"
61 #include "vm/jit/methodheader.h"
62 #include "vm/jit/replace.hpp"
63 #include "vm/jit/show.hpp"
64 #include "vm/jit/stack.h"
67 #define REPLACE_PATCH_DYNAMIC_CALL
68 /*#define REPLACE_PATCH_ALL*/
70 #if defined(ENABLE_VMLOG)
71 #include <vmlog_cacao.h>
74 /*** architecture-dependent configuration *************************************/
76 /* first unset the macros (default) */
77 #undef REPLACE_RA_BETWEEN_FRAMES
78 #undef REPLACE_RA_TOP_OF_FRAME
79 #undef REPLACE_RA_LINKAGE_AREA
80 #undef REPLACE_LEAFMETHODS_RA_REGISTER
82 /* i386, x86_64 and m68k */
83 #if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
84 #define REPLACE_RA_BETWEEN_FRAMES
86 #elif defined(__ALPHA__)
87 #define REPLACE_RA_TOP_OF_FRAME
88 #define REPLACE_LEAFMETHODS_RA_REGISTER
90 #elif defined(__POWERPC__)
91 #define REPLACE_RA_LINKAGE_AREA
92 #define REPLACE_LEAFMETHODS_RA_REGISTER
94 #elif defined(__S390__)
95 #define REPLACE_RA_TOP_OF_FRAME
99 /*** configuration of native stack slot size **********************************/
101 /* XXX this should be in md-abi.h files, probably */
103 #define SIZE_OF_STACKSLOT 8
104 #define STACK_SLOTS_PER_FLOAT 1
105 typedef u8 stackslot_t;
108 /*** debugging ****************************************************************/
111 static void java_value_print(s4 type, replace_val_t value);
112 static void replace_stackframeinfo_println(stackframeinfo_t *sfi);
116 #define DOLOG(code) do{ if (opt_TraceReplacement > 1) { code; } } while(0)
117 #define DOLOG_SHORT(code) do{ if (opt_TraceReplacement > 0) { code; } } while(0)
120 #define DOLOG_SHORT(code)
124 /*** statistics ***************************************************************/
126 #define REPLACE_STATISTICS
128 #if defined(REPLACE_STATISTICS)
130 static int stat_replacements = 0;
131 static int stat_frames = 0;
132 static int stat_recompile = 0;
133 static int stat_staticpatch = 0;
134 static int stat_unroll_inline = 0;
135 static int stat_unroll_call = 0;
136 static int stat_dist_frames[20] = { 0 };
137 static int stat_dist_locals[20] = { 0 };
138 static int stat_dist_locals_adr[10] = { 0 };
139 static int stat_dist_locals_prim[10] = { 0 };
140 static int stat_dist_locals_ret[10] = { 0 };
141 static int stat_dist_locals_void[10] = { 0 };
142 static int stat_dist_stack[10] = { 0 };
143 static int stat_dist_stack_adr[10] = { 0 };
144 static int stat_dist_stack_prim[10] = { 0 };
145 static int stat_dist_stack_ret[10] = { 0 };
146 static int stat_methods = 0;
147 static int stat_rploints = 0;
148 static int stat_regallocs = 0;
149 static int stat_dist_method_rplpoints[20] = { 0 };
151 #define REPLACE_COUNT(cnt) (cnt)++
152 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
153 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
155 #define REPLACE_COUNT_DIST(array, val) \
157 int limit = (sizeof(array) / sizeof(int)) - 1; \
158 if ((val) < (limit)) (array)[val]++; \
159 else (array)[limit]++; \
162 static void replace_statistics_source_frame(sourceframe_t *frame);
166 #define REPLACE_COUNT(cnt)
167 #define REPLACE_COUNT_IF(cnt, cond)
168 #define REPLACE_COUNT_INC(cnt, inc)
169 #define REPLACE_COUNT_DIST(array, val)
171 #endif /* defined(REPLACE_STATISTICS) */
174 /*** constants used internally ************************************************/
176 #define TOP_IS_NORMAL 0
177 #define TOP_IS_ON_STACK 1
178 #define TOP_IS_IN_ITMP1 2
179 #define TOP_IS_VOID 3
182 /******************************************************************************/
183 /* PART I: Creating / freeing replacement points */
184 /******************************************************************************/
187 /* replace_create_replacement_point ********************************************
189 Create a replacement point.
192 jd...............current jitdata
193 iinfo............inlining info for the current position
194 rp...............pre-allocated (uninitialized) rplpoint
195 type.............RPLPOINT_TYPE constant
196 iptr.............current instruction
197 *pra.............current rplalloc pointer
198 javalocals.......the javalocals at the current point
199 stackvars........the stack variables at the current point
200 stackdepth.......the stack depth at the current point
201 paramcount.......number of parameters at the start of stackvars
204 *rpa.............points to the next free rplalloc
206 *******************************************************************************/
208 static void replace_create_replacement_point(jitdata *jd,
209 insinfo_inline *iinfo,
226 REPLACE_COUNT(stat_rploints);
228 rp->method = (iinfo) ? iinfo->method : jd->m;
229 rp->pc = NULL; /* set by codegen */
230 rp->callsize = 0; /* set by codegen */
234 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
236 /* XXX unify these two fields */
237 rp->parent = (iinfo) ? iinfo->rp : NULL;
239 /* store local allocation info of javalocals */
242 for (i = 0; i < rp->method->maxlocals; ++i) {
243 index = javalocals[i];
250 ra->flags = v->flags & (INMEMORY);
251 ra->regoff = v->vv.regoff;
255 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
263 /* store allocation info of java stack vars */
265 for (i = 0; i < stackdepth; ++i) {
266 v = VAR(stackvars[i]);
267 ra->flags = v->flags & (INMEMORY);
268 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
270 /* XXX how to handle locals on the stack containing returnAddresses? */
271 if (v->type == TYPE_RET) {
272 assert(stackvars[i] >= jd->localcount);
273 ra->regoff = v->vv.retaddr->nr;
276 ra->regoff = v->vv.regoff;
280 /* total number of allocations */
282 rp->regalloccount = ra - rp->regalloc;
288 /* replace_create_inline_start_replacement_point *******************************
290 Create an INLINE_START replacement point.
293 jd...............current jitdata
294 rp...............pre-allocated (uninitialized) rplpoint
295 iptr.............current instruction
296 *pra.............current rplalloc pointer
297 javalocals.......the javalocals at the current point
300 *rpa.............points to the next free rplalloc
303 the insinfo_inline * for the following inlined body
305 *******************************************************************************/
307 static insinfo_inline * replace_create_inline_start_replacement_point(
314 insinfo_inline *calleeinfo;
317 calleeinfo = iptr->sx.s23.s3.inlineinfo;
321 replace_create_replacement_point(jd, calleeinfo->parent, rp,
322 RPLPOINT_TYPE_INLINE, iptr, pra,
324 calleeinfo->stackvars, calleeinfo->stackvarscount,
325 calleeinfo->paramcount);
327 if (calleeinfo->synclocal != UNUSED) {
329 ra->index = RPLALLOC_SYNC;
330 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
331 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
341 /* replace_create_replacement_points *******************************************
343 Create the replacement points for the given code.
346 jd...............current jitdata, must not have any replacement points
349 code->rplpoints.......set to the list of replacement points
350 code->rplpointcount...number of replacement points
351 code->regalloc........list of allocation info
352 code->regalloccount...total length of allocation info list
353 code->globalcount.....number of global allocations at the
354 start of code->regalloc
357 true.............everything ok
358 false............an exception has been thrown
360 *******************************************************************************/
362 #define CLEAR_javalocals(array, method) \
364 for (i=0; i<(method)->maxlocals; ++i) \
365 (array)[i] = UNUSED; \
368 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
370 if ((array) != NULL) \
371 MCOPY((dest), (array), s4, (method)->maxlocals); \
373 CLEAR_javalocals((dest), (method)); \
376 #define COUNT_javalocals(array, method, counter) \
378 for (i=0; i<(method)->maxlocals; ++i) \
379 if ((array)[i] != UNUSED) \
383 bool replace_create_replacement_points(jitdata *jd)
401 insinfo_inline *iinfo;
404 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
408 REPLACE_COUNT(stat_methods);
410 /* get required compiler data */
415 /* assert that we wont overwrite already allocated data */
419 assert(code->rplpoints == NULL);
420 assert(code->rplpointcount == 0);
421 assert(code->regalloc == NULL);
422 assert(code->regalloccount == 0);
423 assert(code->globalcount == 0);
427 /* in instance methods, we may need a rplpoint at the method entry */
429 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
430 if (!(m->flags & ACC_STATIC)) {
431 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
437 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
439 /* iterate over the basic block list to find replacement points */
444 javalocals = (s4*) DumpMemory::allocate(sizeof(s4) * jd->maxlocals);
446 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
450 if (bptr->flags < BBFINISHED)
453 /* get info about this block */
456 iinfo = bptr->inlineinfo;
458 /* initialize javalocals at the start of this block */
460 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
462 /* iterate over the instructions */
465 iend = iptr + bptr->icount;
469 for (; iptr != iend; ++iptr) {
471 #if defined(ENABLE_GC_CACAO)
473 md = iptr->sx.s23.s3.bte->md;
475 COUNT_javalocals(javalocals, m, alloccount);
476 alloccount += iptr->s1.argcount;
478 alloccount -= iinfo->throughcount;
482 case ICMD_INVOKESTATIC:
483 case ICMD_INVOKESPECIAL:
484 case ICMD_INVOKEVIRTUAL:
485 case ICMD_INVOKEINTERFACE:
486 INSTRUCTION_GET_METHODDESC(iptr, md);
488 COUNT_javalocals(javalocals, m, alloccount);
489 alloccount += iptr->s1.argcount;
491 alloccount -= iinfo->throughcount;
499 stack_javalocals_store(iptr, javalocals);
513 case ICMD_INLINE_START:
514 iinfo = iptr->sx.s23.s3.inlineinfo;
517 COUNT_javalocals(javalocals, m, alloccount);
518 alloccount += iinfo->stackvarscount;
519 if (iinfo->synclocal != UNUSED)
523 /* javalocals may be set at next block start, or now */
524 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
527 case ICMD_INLINE_BODY:
528 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
530 jl = iinfo->javalocals_start;
532 /* get the javalocals from the following block start */
534 jl = bptr->next->javalocals;
537 COUNT_javalocals(jl, m, alloccount);
540 case ICMD_INLINE_END:
541 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
542 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
543 iinfo = iptr->sx.s23.s3.inlineinfo;
545 if (iinfo->javalocals_end)
546 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
547 iinfo = iinfo->parent;
551 if (iptr == bptr->iinstr)
553 } /* end instruction loop */
555 /* create replacement points at targets of backward branches */
556 /* We only need the replacement point there, if there is no */
557 /* replacement point inside the block. */
559 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
560 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
561 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
565 if (test > startcount) {
566 /* we don't need an extra rplpoint */
567 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
571 alloccount += bptr->indepth;
572 if (bptr->inlineinfo)
573 alloccount -= bptr->inlineinfo->throughcount;
575 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
579 } /* end basicblock loop */
581 /* if no points were found, there's nothing to do */
586 /* allocate replacement point array and allocation array */
588 rplpoints = MNEW(rplpoint, count);
589 regalloc = MNEW(rplalloc, alloccount);
592 /* initialize replacement point structs */
596 /* XXX try to share code with the counting loop! */
598 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
601 if (bptr->flags < BBFINISHED)
604 /* get info about this block */
607 iinfo = bptr->inlineinfo;
609 /* initialize javalocals at the start of this block */
611 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
613 /* create replacement points at targets of backward branches */
615 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
617 i = (iinfo) ? iinfo->throughcount : 0;
618 replace_create_replacement_point(jd, iinfo, rp++,
619 bptr->type, bptr->iinstr, &ra,
620 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
622 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
623 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
626 /* iterate over the instructions */
629 iend = iptr + bptr->icount;
631 for (; iptr != iend; ++iptr) {
633 #if defined(ENABLE_GC_CACAO)
635 md = iptr->sx.s23.s3.bte->md;
637 i = (iinfo) ? iinfo->throughcount : 0;
638 replace_create_replacement_point(jd, iinfo, rp++,
639 RPLPOINT_TYPE_CALL, iptr, &ra,
640 javalocals, iptr->sx.s23.s2.args,
641 iptr->s1.argcount - i,
646 case ICMD_INVOKESTATIC:
647 case ICMD_INVOKESPECIAL:
648 case ICMD_INVOKEVIRTUAL:
649 case ICMD_INVOKEINTERFACE:
650 INSTRUCTION_GET_METHODDESC(iptr, md);
652 i = (iinfo) ? iinfo->throughcount : 0;
653 replace_create_replacement_point(jd, iinfo, rp++,
654 RPLPOINT_TYPE_CALL, iptr, &ra,
655 javalocals, iptr->sx.s23.s2.args,
656 iptr->s1.argcount - i,
665 stack_javalocals_store(iptr, javalocals);
673 replace_create_replacement_point(jd, iinfo, rp++,
674 RPLPOINT_TYPE_RETURN, iptr, &ra,
675 NULL, &(iptr->s1.varindex), 1, 0);
679 replace_create_replacement_point(jd, iinfo, rp++,
680 RPLPOINT_TYPE_RETURN, iptr, &ra,
684 case ICMD_INLINE_START:
685 iinfo = replace_create_inline_start_replacement_point(
686 jd, rp++, iptr, &ra, javalocals);
688 /* javalocals may be set at next block start, or now */
689 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
692 case ICMD_INLINE_BODY:
693 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
695 jl = iinfo->javalocals_start;
697 /* get the javalocals from the following block start */
699 jl = bptr->next->javalocals;
701 /* create a non-trappable rplpoint */
702 replace_create_replacement_point(jd, iinfo, rp++,
703 RPLPOINT_TYPE_BODY, iptr, &ra,
705 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
708 case ICMD_INLINE_END:
709 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
710 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
711 iinfo = iptr->sx.s23.s3.inlineinfo;
713 if (iinfo->javalocals_end)
714 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
715 iinfo = iinfo->parent;
718 } /* end instruction loop */
719 } /* end basicblock loop */
721 assert((rp - rplpoints) == count);
722 assert((ra - regalloc) == alloccount);
724 /* store the data in the codeinfo */
726 code->rplpoints = rplpoints;
727 code->rplpointcount = count;
728 code->regalloc = regalloc;
729 code->regalloccount = alloccount;
730 code->globalcount = 0;
731 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
732 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
733 #if defined(HAS_ADDRESS_REGISTER_FILE)
734 code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
736 code->memuse = rd->memuse;
737 code->stackframesize = jd->cd->stackframesize;
739 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
740 REPLACE_COUNT_INC(stat_regallocs, alloccount);
742 /* everything alright */
748 /* replace_free_replacement_points *********************************************
750 Free memory used by replacement points.
753 code.............codeinfo whose replacement points should be freed.
755 *******************************************************************************/
757 void replace_free_replacement_points(codeinfo *code)
762 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
765 MFREE(code->regalloc,rplalloc,code->regalloccount);
767 code->rplpoints = NULL;
768 code->rplpointcount = 0;
769 code->regalloc = NULL;
770 code->regalloccount = 0;
771 code->globalcount = 0;
775 /******************************************************************************/
776 /* PART II: Activating / deactivating replacement points */
777 /******************************************************************************/
780 /* replace_activate_replacement_points *****************************************
782 Activate the replacement points of the given compilation unit. When this
783 function returns, the replacement points are "armed", so each thread
784 reaching one of the points will enter the replacement mechanism.
787 code.............codeinfo of which replacement points should be
789 mappable.........if true, only mappable replacement points are
792 *******************************************************************************/
794 void replace_activate_replacement_points(codeinfo *code, bool mappable)
801 assert(code->savedmcode == NULL);
803 /* count trappable replacement points */
806 i = code->rplpointcount;
807 rp = code->rplpoints;
809 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
812 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
818 /* allocate buffer for saved machine code */
820 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
821 code->savedmcode = savedmcode;
822 savedmcode += count * REPLACEMENT_PATCH_SIZE;
824 /* activate trappable replacement points */
825 /* (in reverse order to handle overlapping points within basic blocks) */
827 i = code->rplpointcount;
828 rp = code->rplpoints + i;
830 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
832 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
835 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
838 DOLOG( printf("activate replacement point:\n");
839 replace_replacement_point_println(rp, 1); fflush(stdout); );
841 savedmcode -= REPLACEMENT_PATCH_SIZE;
843 #if defined(ENABLE_JIT)
844 # if defined(ENABLE_DISASSEMBLER)
845 DOLOG( printf("\tinstruction before: ");
846 disassinstr(rp->pc); fflush(stdout); );
849 md_patch_replacement_point(rp->pc, savedmcode, false);
851 # if defined(ENABLE_DISASSEMBLER)
852 DOLOG( printf("\tinstruction after : ");
853 disassinstr(rp->pc); fflush(stdout); );
857 rp->flags |= RPLPOINT_FLAG_ACTIVE;
860 assert(savedmcode == code->savedmcode);
864 /* replace_deactivate_replacement_points ***************************************
866 Deactivate a replacement points in the given compilation unit.
867 When this function returns, the replacement points will be "un-armed",
868 that is a each thread reaching a point will just continue normally.
871 code.............the compilation unit
873 *******************************************************************************/
875 void replace_deactivate_replacement_points(codeinfo *code)
882 if (code->savedmcode == NULL) {
883 /* disarm countdown points by patching the branches */
885 i = code->rplpointcount;
886 rp = code->rplpoints;
888 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
889 == RPLPOINT_FLAG_COUNTDOWN)
892 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
899 assert(code->savedmcode != NULL);
900 savedmcode = code->savedmcode;
902 /* de-activate each trappable replacement point */
904 i = code->rplpointcount;
905 rp = code->rplpoints;
908 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
913 DOLOG( printf("deactivate replacement point:\n");
914 replace_replacement_point_println(rp, 1); fflush(stdout); );
916 #if defined(ENABLE_JIT)
917 # if defined(ENABLE_DISASSEMBLER)
918 DOLOG( printf("\tinstruction before: ");
919 disassinstr(rp->pc); fflush(stdout); );
922 md_patch_replacement_point(rp->pc, savedmcode, true);
924 # if defined(ENABLE_DISASSEMBLER)
925 DOLOG( printf("\tinstruction before: ");
926 disassinstr(rp->pc); fflush(stdout); );
930 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
932 savedmcode += REPLACEMENT_PATCH_SIZE;
935 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
937 /* free saved machine code */
939 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
940 code->savedmcode = NULL;
944 /******************************************************************************/
945 /* PART III: The replacement mechanism */
946 /******************************************************************************/
949 /* replace_read_value **********************************************************
951 Read a value with the given allocation from the execution state.
954 es...............execution state
955 ra...............allocation
956 javaval..........where to put the value
959 *javaval.........the value
961 *******************************************************************************/
963 static void replace_read_value(executionstate_t *es,
965 replace_val_t *javaval)
967 if (ra->flags & INMEMORY) {
968 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
969 #ifdef HAS_4BYTE_STACKSLOT
970 if (IS_2_WORD_TYPE(ra->type)) {
971 javaval->l = *(u8*)(es->sp + ra->regoff);
975 javaval->p = *(ptrint*)(es->sp + ra->regoff);
976 #ifdef HAS_4BYTE_STACKSLOT
981 /* allocated register */
982 if (IS_FLT_DBL_TYPE(ra->type)) {
983 javaval->d = es->fltregs[ra->regoff];
985 if (ra->type == TYPE_FLT)
986 javaval->f = javaval->d;
988 #if defined(HAS_ADDRESS_REGISTER_FILE)
989 else if (IS_ADR_TYPE(ra->type)) {
990 javaval->p = es->adrregs[ra->regoff];
994 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
995 if (ra->type == TYPE_LNG) {
996 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
997 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
1000 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
1001 javaval->p = es->intregs[ra->regoff];
1007 /* replace_write_value *********************************************************
1009 Write a value to the given allocation in the execution state.
1012 es...............execution state
1013 ra...............allocation
1014 *javaval.........the value
1016 *******************************************************************************/
1018 static void replace_write_value(executionstate_t *es,
1020 replace_val_t *javaval)
1022 if (ra->flags & INMEMORY) {
1023 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1024 #ifdef HAS_4BYTE_STACKSLOT
1025 if (IS_2_WORD_TYPE(ra->type)) {
1026 *(u8*)(es->sp + ra->regoff) = javaval->l;
1030 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1031 #ifdef HAS_4BYTE_STACKSLOT
1036 /* allocated register */
1039 es->fltregs[ra->regoff] = (double) javaval->f;
1042 es->fltregs[ra->regoff] = javaval->d;
1044 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1046 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1047 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1050 #if defined(HAS_ADDRESS_REGISTER_FILE)
1052 es->adrregs[ra->regoff] = javaval->p;
1055 es->intregs[ra->regoff] = javaval->p;
1061 /* replace_new_sourceframe *****************************************************
1063 Allocate a new source frame and insert it at the front of the frame list.
1066 ss...............the source state
1069 ss->frames.......set to new frame (the new head of the frame list).
1072 returns the new frame
1074 *******************************************************************************/
1076 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1078 sourceframe_t *frame;
1080 frame = (sourceframe_t*) DumpMemory::allocate(sizeof(sourceframe_t));
1081 MZERO(frame, sourceframe_t, 1);
1083 frame->down = ss->frames;
1090 /* replace_read_executionstate *************************************************
1092 Read a source frame from the given executions state.
1093 The new source frame is pushed to the front of the frame list of the
1097 rp...............replacement point at which `es` was taken
1098 es...............execution state
1099 ss...............the source state to add the source frame to
1100 topframe.........true, if the first (top-most) source frame on the
1104 *ss..............the source state with the newly created source frame
1107 *******************************************************************************/
1109 static s4 replace_normalize_type_map[] = {
1110 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1111 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1112 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1113 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1114 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1115 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1116 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1120 static void replace_read_executionstate(rplpoint *rp,
1121 executionstate_t *es,
1130 sourceframe_t *frame;
1133 stackslot_t *basesp;
1135 code = code_find_codeinfo_for_pc(rp->pc);
1137 topslot = TOP_IS_NORMAL;
1141 sp = (stackslot_t *) es->sp;
1143 /* in some cases the top stack slot is passed in REG_ITMP1 */
1145 if (rp->type == BBTYPE_EXH) {
1146 topslot = TOP_IS_IN_ITMP1;
1149 /* calculate base stack pointer */
1151 basesp = sp + code->stackframesize;
1153 /* create the source frame */
1155 frame = replace_new_sourceframe(ss);
1156 frame->method = rp->method;
1158 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1159 frame->type = replace_normalize_type_map[rp->type];
1161 frame->fromcode = code;
1163 /* read local variables */
1165 count = m->maxlocals;
1166 frame->javalocalcount = count;
1167 frame->javalocals = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1168 frame->javalocaltype = (u1*) DumpMemory::allocate(sizeof(u1) * count);
1170 /* mark values as undefined */
1171 for (i=0; i<count; ++i) {
1172 #if !defined(NDEBUG)
1173 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1175 frame->javalocaltype[i] = TYPE_VOID;
1178 /* some entries in the intregs array are not meaningful */
1179 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1180 #if !defined(NDEBUG)
1181 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1183 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1185 #endif /* !defined(NDEBUG) */
1187 /* read javalocals */
1189 count = rp->regalloccount;
1192 while (count && (i = ra->index) >= 0) {
1193 assert(i < m->maxlocals);
1194 frame->javalocaltype[i] = ra->type;
1195 if (ra->type == TYPE_RET)
1196 frame->javalocals[i].i = ra->regoff;
1198 replace_read_value(es, ra, frame->javalocals + i);
1203 /* read instance, if this is the first rplpoint */
1205 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1206 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1208 /* we are at the start of the method body, so if local 0 is set, */
1209 /* it is the instance. */
1210 if (frame->javalocaltype[0] == TYPE_ADR)
1211 frame->instance = frame->javalocals[0];
1216 md = rp->method->parseddesc;
1218 assert(md->paramcount >= 1);
1219 instra.type = TYPE_ADR;
1220 instra.regoff = md->params[0].regoff;
1221 if (md->params[0].inmemory) {
1222 instra.flags = INMEMORY;
1223 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1228 replace_read_value(es, &instra, &(frame->instance));
1231 #if defined(__I386__)
1232 else if (!(rp->method->flags & ACC_STATIC)) {
1233 /* On i386 we always pass the first argument on stack. */
1234 frame->instance.a = *(java_object_t **)(basesp + 1);
1237 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1239 /* read stack slots */
1241 frame->javastackdepth = count;
1242 frame->javastack = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1243 frame->javastacktype = (u1*) DumpMemory::allocate(sizeof(u1) * count);
1245 #if !defined(NDEBUG)
1246 /* mark values as undefined */
1247 for (i=0; i<count; ++i) {
1248 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1249 frame->javastacktype[i] = TYPE_VOID;
1251 #endif /* !defined(NDEBUG) */
1255 /* the first stack slot is special in SBR and EXH blocks */
1257 if (topslot == TOP_IS_ON_STACK) {
1260 assert(ra->index == RPLALLOC_STACK);
1261 assert(ra->type == TYPE_ADR);
1262 frame->javastack[i].p = sp[-1];
1263 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1268 else if (topslot == TOP_IS_IN_ITMP1) {
1271 assert(ra->index == RPLALLOC_STACK);
1272 assert(ra->type == TYPE_ADR);
1273 frame->javastack[i].p = es->intregs[REG_ITMP1];
1274 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1279 else if (topslot == TOP_IS_VOID) {
1282 assert(ra->index == RPLALLOC_STACK);
1283 frame->javastack[i].l = 0;
1284 frame->javastacktype[i] = TYPE_VOID;
1290 /* read remaining stack slots */
1292 for (; count--; ra++) {
1293 if (ra->index == RPLALLOC_SYNC) {
1294 assert(rp->type == RPLPOINT_TYPE_INLINE);
1296 /* only read synchronization slots when traversing an inline point */
1299 sourceframe_t *calleeframe = frame->down;
1300 assert(calleeframe);
1301 assert(calleeframe->syncslotcount == 0);
1302 assert(calleeframe->syncslots == NULL);
1304 calleeframe->syncslotcount = 1;
1305 calleeframe->syncslots = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t));
1306 replace_read_value(es,ra,calleeframe->syncslots);
1309 frame->javastackdepth--;
1313 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1315 /* do not read parameters of calls down the call chain */
1317 if (!topframe && ra->index == RPLALLOC_PARAM) {
1318 frame->javastackdepth--;
1321 if (ra->type == TYPE_RET)
1322 frame->javastack[i].i = ra->regoff;
1324 replace_read_value(es,ra,frame->javastack + i);
1325 frame->javastacktype[i] = ra->type;
1332 /* replace_write_executionstate ************************************************
1334 Pop a source frame from the front of the frame list of the given source state
1335 and write its values into the execution state.
1338 rp...............replacement point for which execution state should be
1340 es...............the execution state to modify
1341 ss...............the given source state
1342 topframe.........true, if this is the last (top-most) source frame to be
1346 *es..............the execution state derived from the source state
1348 *******************************************************************************/
1350 static void replace_write_executionstate(rplpoint *rp,
1351 executionstate_t *es,
1360 sourceframe_t *frame;
1363 stackslot_t *basesp;
1365 code = code_find_codeinfo_for_pc(rp->pc);
1367 topslot = TOP_IS_NORMAL;
1369 /* pop a source frame */
1373 ss->frames = frame->down;
1375 /* calculate stack pointer */
1377 sp = (stackslot_t *) es->sp;
1379 basesp = sp + code->stackframesize;
1381 /* in some cases the top stack slot is passed in REG_ITMP1 */
1383 if (rp->type == BBTYPE_EXH) {
1384 topslot = TOP_IS_IN_ITMP1;
1387 /* write javalocals */
1390 count = rp->regalloccount;
1392 while (count && (i = ra->index) >= 0) {
1393 assert(i < m->maxlocals);
1394 assert(i < frame->javalocalcount);
1395 assert(ra->type == frame->javalocaltype[i]);
1396 if (ra->type == TYPE_RET) {
1397 /* XXX assert that it matches this rplpoint */
1400 replace_write_value(es, ra, frame->javalocals + i);
1405 /* write stack slots */
1409 /* the first stack slot is special in SBR and EXH blocks */
1411 if (topslot == TOP_IS_ON_STACK) {
1414 assert(ra->index == RPLALLOC_STACK);
1415 assert(i < frame->javastackdepth);
1416 assert(frame->javastacktype[i] == TYPE_ADR);
1417 sp[-1] = frame->javastack[i].p;
1422 else if (topslot == TOP_IS_IN_ITMP1) {
1425 assert(ra->index == RPLALLOC_STACK);
1426 assert(i < frame->javastackdepth);
1427 assert(frame->javastacktype[i] == TYPE_ADR);
1428 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1433 else if (topslot == TOP_IS_VOID) {
1436 assert(ra->index == RPLALLOC_STACK);
1437 assert(i < frame->javastackdepth);
1438 assert(frame->javastacktype[i] == TYPE_VOID);
1444 /* write remaining stack slots */
1446 for (; count--; ra++) {
1447 if (ra->index == RPLALLOC_SYNC) {
1448 assert(rp->type == RPLPOINT_TYPE_INLINE);
1450 /* only write synchronization slots when traversing an inline point */
1453 assert(frame->down);
1454 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1455 assert(frame->down->syncslots != NULL);
1457 replace_write_value(es,ra,frame->down->syncslots);
1462 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1464 /* do not write parameters of calls down the call chain */
1466 if (!topframe && ra->index == RPLALLOC_PARAM) {
1469 ra->index = RPLALLOC_PARAM;
1472 replace_write_value(es,ra,&v);
1476 assert(i < frame->javastackdepth);
1477 assert(ra->type == frame->javastacktype[i]);
1478 if (ra->type == TYPE_RET) {
1479 /* XXX assert that it matches this rplpoint */
1482 replace_write_value(es,ra,frame->javastack + i);
1494 /* md_pop_stackframe ***********************************************************
1496 Restore callee-saved registers (including the RA register),
1497 set the stack pointer to the next stackframe,
1498 set the PC to the return address of the popped frame.
1500 *** This function imitates the effects of the method epilog ***
1501 *** and returning from the method call. ***
1504 es...............execution state
1507 *es..............the execution state after popping the stack frame
1508 NOTE: es->code and es->pv are NOT updated.
1510 *******************************************************************************/
1512 void md_pop_stackframe(executionstate_t *es)
1518 stackslot_t *basesp;
1523 /* alignment offset of RA */
1526 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1527 if (es->code->stackframesize)
1528 ra_align_off = SIZE_OF_STACKSLOT - SIZEOF_VOID_P;
1531 /* read the return address */
1533 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1534 if (code_is_leafmethod(es->code))
1538 ra = (u1*) md_stacktrace_get_returnaddress(es->sp,
1539 SIZE_OF_STACKSLOT * es->code->stackframesize + ra_align_off);
1541 /* calculate the base of the stack frame */
1543 sp = (stackslot_t *) es->sp;
1544 basesp = sp + es->code->stackframesize;
1546 /* restore return address, if part of frame */
1548 #if defined(REPLACE_RA_TOP_OF_FRAME)
1549 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1550 if (!code_is_leafmethod(es->code))
1552 es->ra = (u1*) (ptrint) *--basesp;
1553 #endif /* REPLACE_RA_TOP_OF_FRAME */
1555 #if defined(REPLACE_RA_LINKAGE_AREA)
1556 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1557 if (!code_is_leafmethod(es->code))
1559 es->ra = (u1*) (ptrint) basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1560 #endif /* REPLACE_RA_LINKAGE_AREA */
1562 /* restore saved int registers */
1565 for (i=0; i<es->code->savedintcount; ++i) {
1566 while (nregdescint[--reg] != REG_SAV)
1568 es->intregs[reg] = *--basesp;
1571 /* restore saved flt registers */
1575 for (i=0; i<es->code->savedfltcount; ++i) {
1576 while (nregdescfloat[--reg] != REG_SAV)
1578 basesp -= STACK_SLOTS_PER_FLOAT;
1579 es->fltregs[reg] = *(double*)basesp;
1582 #if defined(HAS_ADDRESS_REGISTER_FILE)
1583 /* restore saved adr registers */
1586 for (i=0; i<es->code->savedadrcount; ++i) {
1587 while (nregdescadr[--reg] != REG_SAV)
1589 es->adrregs[reg] = *--basesp;
1593 /* adjust the stackpointer */
1595 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1597 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1598 es->sp += ra_align_off + SIZEOF_VOID_P; /* skip return address */
1601 /* set the program counter to the return address */
1605 /* in debugging mode clobber non-saved registers */
1607 #if !defined(NDEBUG)
1609 for (i=0; i<INT_REG_CNT; ++i)
1610 if (nregdescint[i] != REG_SAV)
1611 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1612 for (i=0; i<FLT_REG_CNT; ++i)
1613 if (nregdescfloat[i] != REG_SAV)
1614 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1615 # if defined(HAS_ADDRESS_REGISTER_FILE)
1616 for (i=0; i<ADR_REG_CNT; ++i)
1617 if (nregdescadr[i] != REG_SAV)
1618 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1620 #endif /* !defined(NDEBUG) */
1624 /* md_push_stackframe **********************************************************
1626 Save the given return address, build the new stackframe,
1627 and store callee-saved registers.
1629 *** This function imitates the effects of a call and the ***
1630 *** method prolog of the callee. ***
1633 es...............execution state
1634 calleecode.......the code we are "calling"
1635 ra...............the return address to save
1638 *es..............the execution state after pushing the stack frame
1639 NOTE: es->pc, es->code, and es->pv are NOT updated.
1641 *******************************************************************************/
1643 void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra)
1647 stackslot_t *basesp;
1653 /* write the return address */
1655 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1656 es->sp -= SIZEOF_VOID_P;
1657 *((void **)es->sp) = (void *) ra;
1658 if (calleecode->stackframesize)
1659 es->sp -= (SIZE_OF_STACKSLOT - SIZEOF_VOID_P);
1660 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1662 es->ra = (u1*) (ptrint) ra;
1664 /* build the stackframe */
1666 DOLOG( printf("building stackframe of %d words at %p\n",
1667 calleecode->stackframesize, (void*)es->sp); );
1669 sp = (stackslot_t *) es->sp;
1672 sp -= calleecode->stackframesize;
1675 /* in debug mode, invalidate stack frame first */
1677 /* XXX may not invalidate linkage area used by native code! */
1679 #if !defined(NDEBUG) && 0
1680 for (i=0; i< (basesp - sp) && i < 1; ++i) {
1681 sp[i] = 0xdeaddeadU;
1685 #if defined(__I386__)
1686 /* Stackslot 0 may contain the object instance for vftbl patching.
1687 Destroy it, so there's no undefined value used. */
1688 if ((basesp - sp) > 0) {
1693 /* save the return address register */
1695 #if defined(REPLACE_RA_TOP_OF_FRAME)
1696 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1697 if (!code_is_leafmethod(calleecode))
1699 *--basesp = (ptrint) ra;
1700 #endif /* REPLACE_RA_TOP_OF_FRAME */
1702 #if defined(REPLACE_RA_LINKAGE_AREA)
1703 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1704 if (!code_is_leafmethod(calleecode))
1706 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1707 #endif /* REPLACE_RA_LINKAGE_AREA */
1709 /* save int registers */
1712 for (i=0; i<calleecode->savedintcount; ++i) {
1713 while (nregdescint[--reg] != REG_SAV)
1715 *--basesp = es->intregs[reg];
1717 /* XXX may not clobber saved regs used by native code! */
1718 #if !defined(NDEBUG) && 0
1719 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1723 /* save flt registers */
1727 for (i=0; i<calleecode->savedfltcount; ++i) {
1728 while (nregdescfloat[--reg] != REG_SAV)
1730 basesp -= STACK_SLOTS_PER_FLOAT;
1731 *(double*)basesp = es->fltregs[reg];
1733 /* XXX may not clobber saved regs used by native code! */
1734 #if !defined(NDEBUG) && 0
1735 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1739 #if defined(HAS_ADDRESS_REGISTER_FILE)
1740 /* save adr registers */
1743 for (i=0; i<calleecode->savedadrcount; ++i) {
1744 while (nregdescadr[--reg] != REG_SAV)
1746 *--basesp = es->adrregs[reg];
1748 /* XXX may not clobber saved regs used by native code! */
1749 #if !defined(NDEBUG) && 0
1750 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1757 /* replace_pop_activation_record ***********************************************
1759 Peel a stack frame from the execution state.
1761 *** This function imitates the effects of the method epilog ***
1762 *** and returning from the method call. ***
1765 es...............execution state
1766 frame............source frame, receives synchronization slots
1769 *es..............the execution state after popping the stack frame
1772 the return address of the poped activation record
1774 *******************************************************************************/
1776 u1* replace_pop_activation_record(executionstate_t *es,
1777 sourceframe_t *frame)
1788 /* calculate the base of the stack frame */
1790 sp = (stackslot_t *) es->sp;
1791 assert(frame->syncslotcount == 0);
1792 assert(frame->syncslots == NULL);
1793 count = code_get_sync_slot_count(es->code);
1794 frame->syncslotcount = count;
1795 frame->syncslots = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1796 for (i=0; i<count; ++i) {
1797 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX md_ function */
1800 /* pop the stackframe */
1802 md_pop_stackframe(es);
1806 DOLOG( printf("RA = %p\n", (void*)ra); );
1808 /* Subtract one from the PC so we do not hit the replacement point */
1809 /* of the instruction following the call, if there is one. */
1813 /* find the new codeinfo */
1815 void* pv = md_codegen_get_pv_from_pc(ra);
1816 DOLOG( printf("PV = %p\n", pv); );
1818 code = code_get_codeinfo_for_pv(pv);
1819 DOLOG( printf("CODE = %p\n", (void*) code); );
1821 /* return NULL if we reached native code */
1823 es->pv = (uint8_t*) pv;
1826 return (code) ? ra : NULL;
1830 /* replace_patch_method_pointer ************************************************
1832 Patch a method pointer (may be in code, data segment, vftbl, or interface
1836 mpp..............address of the method pointer to patch
1837 entrypoint.......the new entrypoint of the method
1838 kind.............kind of call to patch, used only for debugging
1840 *******************************************************************************/
1842 static void replace_patch_method_pointer(methodptr *mpp,
1843 methodptr entrypoint,
1846 #if !defined(NDEBUG)
1851 DOLOG( printf("patch method pointer from: %p to %p\n",
1852 (void*) *mpp, (void*)entrypoint); );
1854 #if !defined(NDEBUG)
1855 oldcode = code_get_codeinfo_for_pv(*mpp);
1856 newcode = code_get_codeinfo_for_pv(entrypoint);
1858 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1859 method_println(oldcode->m);
1860 printf("\t with %p ", (void*) newcode);
1861 method_println(newcode->m); );
1863 assert(oldcode->m == newcode->m);
1866 /* write the new entrypoint */
1868 *mpp = (methodptr) entrypoint;
1872 /* replace_patch_class *********************************************************
1874 Patch a method in the given class.
1877 vftbl............vftbl of the class
1878 m................the method to patch
1879 oldentrypoint....the old entrypoint to replace
1880 entrypoint.......the new entrypoint
1882 *******************************************************************************/
1884 void replace_patch_class(vftbl_t *vftbl,
1893 /* patch the vftbl of the class */
1895 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1899 /* patch the interface tables */
1901 assert(oldentrypoint);
1903 for (i=0; i < vftbl->interfacetablelength; ++i) {
1904 mpp = vftbl->interfacetable[-i];
1905 mppend = mpp + vftbl->interfacevftbllength[i];
1906 for (; mpp != mppend; ++mpp)
1907 if (*mpp == oldentrypoint) {
1908 replace_patch_method_pointer(mpp, entrypoint, "interface");
1914 /* replace_patch_class_hierarchy ***********************************************
1916 Patch a method in all loaded classes.
1919 m................the method to patch
1920 oldentrypoint....the old entrypoint to replace
1921 entrypoint.......the new entrypoint
1923 *******************************************************************************/
1925 struct replace_patch_data_t {
1931 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1933 vftbl_t *vftbl = c->vftbl;
1936 && vftbl->vftbllength > pd->m->vftblindex
1937 && (void*) vftbl->table[pd->m->vftblindex] != (void*) (uintptr_t) &asm_abstractmethoderror
1938 && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
1940 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1944 void replace_patch_class_hierarchy(methodinfo *m,
1948 struct replace_patch_data_t pd;
1951 pd.oldentrypoint = oldentrypoint;
1952 pd.entrypoint = entrypoint;
1954 DOLOG_SHORT( printf("patching class hierarchy: ");
1955 method_println(m); );
1957 classcache_foreach_loaded_class(
1958 (classcache_foreach_functionptr_t) &replace_patch_callback,
1963 /* replace_patch_future_calls **************************************************
1965 Analyse a call site and depending on the kind of call patch the call, the
1966 virtual function table, or the interface table.
1969 ra...............return address pointing after the call site
1970 callerframe......source frame of the caller
1971 calleeframe......source frame of the callee, must have been mapped
1973 *******************************************************************************/
1975 void replace_patch_future_calls(u1 *ra,
1976 sourceframe_t *callerframe,
1977 sourceframe_t *calleeframe)
1980 methodptr entrypoint;
1981 methodptr oldentrypoint;
1984 codeinfo *calleecode;
1985 methodinfo *calleem;
1990 assert(callerframe->down == calleeframe);
1992 /* get the new codeinfo and the method that shall be entered */
1994 calleecode = calleeframe->tocode;
1997 calleem = calleeframe->method;
1998 assert(calleem == calleecode->m);
2000 entrypoint = (methodptr) calleecode->entrypoint;
2002 /* check if we are at an method entry rplpoint at the innermost frame */
2004 atentry = (calleeframe->down == NULL)
2005 && !(calleem->flags & ACC_STATIC)
2006 && (calleeframe->fromrp->id == 0); /* XXX */
2008 /* get the position to patch, in case it was a statically bound call */
2010 pv = callerframe->fromcode->entrypoint;
2011 patchpos = (u1*) md_jit_method_patch_address(pv, ra, NULL);
2013 if (patchpos == NULL) {
2014 /* the call was dispatched dynamically */
2016 /* we can only patch such calls if we are at the entry point */
2018 #if !defined(__I386__)
2019 /* On i386 we always know the instance argument. */
2024 assert((calleem->flags & ACC_STATIC) == 0);
2026 oldentrypoint = calleeframe->fromcode->entrypoint;
2028 /* we need to know the instance */
2030 if (!calleeframe->instance.a) {
2031 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
2032 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
2038 obj = calleeframe->instance.a;
2041 assert(vftbl->clazz->vftbl == vftbl);
2043 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->clazz); );
2045 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
2048 /* the call was statically bound */
2050 #if defined(__I386__)
2051 /* It happens that there is a patcher trap. (pm) */
2052 if (*(u2 *)(patchpos - 1) == 0x0b0f) {
2055 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
2060 /* replace_push_activation_record **********************************************
2062 Push a stack frame onto the execution state.
2064 *** This function imitates the effects of a call and the ***
2065 *** method prolog of the callee. ***
2068 es...............execution state
2069 rpcall...........the replacement point at the call site
2070 callerframe......source frame of the caller, or NULL for creating the
2072 calleeframe......source frame of the callee, must have been mapped
2075 *es..............the execution state after pushing the stack frame
2077 *******************************************************************************/
2079 void replace_push_activation_record(executionstate_t *es,
2081 sourceframe_t *callerframe,
2082 sourceframe_t *calleeframe)
2088 codeinfo *calleecode;
2091 assert(!rpcall || callerframe);
2092 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
2093 assert(!rpcall || rpcall == callerframe->torp);
2094 assert(calleeframe);
2095 assert(!callerframe || calleeframe == callerframe->down);
2097 /* the compilation unit we are entering */
2099 calleecode = calleeframe->tocode;
2102 /* calculate the return address */
2105 ra = rpcall->pc + rpcall->callsize;
2107 ra = es->pc + 1 /* XXX this is ugly */;
2109 /* push the stackframe */
2111 md_push_stackframe(es, calleecode, ra);
2113 /* we move into a new code unit, set code, PC, PV */
2115 es->code = calleecode;
2116 es->pc = calleecode->entrypoint; /* XXX not needed? */
2117 es->pv = calleecode->entrypoint;
2119 /* write slots used for synchronization */
2121 sp = (stackslot_t *) es->sp;
2122 count = code_get_sync_slot_count(calleecode);
2123 assert(count == calleeframe->syncslotcount);
2124 for (i=0; i<count; ++i) {
2125 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2128 /* redirect future invocations */
2130 if (callerframe && rpcall) {
2131 #if defined(REPLACE_PATCH_ALL)
2132 if (rpcall->type == callerframe->fromrp->type)
2134 if (rpcall == callerframe->fromrp)
2136 replace_patch_future_calls(ra, callerframe, calleeframe);
2141 /* replace_find_replacement_point **********************************************
2143 Find the replacement point in the given code corresponding to the
2144 position given in the source frame.
2147 code.............the codeinfo in which to search the rplpoint
2148 frame............the source frame defining the position to look for
2149 parent...........parent replacement point to match
2152 the replacement point
2154 *******************************************************************************/
2156 rplpoint * replace_find_replacement_point(codeinfo *code,
2157 sourceframe_t *frame,
2170 DOLOG( printf("searching replacement point for:\n");
2171 replace_source_frame_println(frame); );
2175 DOLOG( printf("code = %p\n", (void*)code); );
2177 rp = code->rplpoints;
2178 i = code->rplpointcount;
2180 if (rp->id == frame->id && rp->method == frame->method
2181 && rp->parent == parent
2182 && replace_normalize_type_map[rp->type] == frame->type)
2184 /* check if returnAddresses match */
2185 /* XXX optimize: only do this if JSRs in method */
2186 DOLOG( printf("checking match for:");
2187 replace_replacement_point_println(rp, 1); fflush(stdout); );
2190 for (j = rp->regalloccount; j--; ++ra) {
2191 if (ra->type == TYPE_RET) {
2192 if (ra->index == RPLALLOC_STACK) {
2193 assert(stacki < frame->javastackdepth);
2194 if (frame->javastack[stacki].i != ra->regoff)
2199 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2200 if (frame->javalocals[ra->index].i != ra->regoff)
2213 #if !defined(NDEBUG)
2214 printf("candidate replacement points were:\n");
2215 rp = code->rplpoints;
2216 i = code->rplpointcount;
2218 replace_replacement_point_println(rp, 1);
2222 vm_abort("no matching replacement point found");
2223 return NULL; /* NOT REACHED */
2227 /* replace_find_replacement_point_for_pc ***************************************
2229 Find the nearest replacement point at or before the given PC. The
2230 given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
2231 the replacement point to be found.
2234 code.............compilation unit the PC is in
2235 pc...............the machine code PC
2238 the replacement point found, or
2239 NULL if no replacement point was found
2241 *******************************************************************************/
2243 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc, unsigned desired_flags)
2249 DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
2250 method_println(code->m); );
2254 rp = code->rplpoints;
2255 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2256 DOLOG( replace_replacement_point_println(rp, 2); );
2257 if (rp->pc <= pc && rp->pc + rp->callsize >= pc) {
2258 if (desired_flags) {
2259 if (rp->flags & desired_flags) {
2271 /* replace_pop_native_frame ****************************************************
2273 Unroll a native frame in the execution state and create a source frame
2277 es...............current execution state
2278 ss...............the current source state
2279 sfi..............stackframeinfo for the native frame
2282 es...............execution state after unrolling the native frame
2283 ss...............gets the added native source frame
2285 *******************************************************************************/
2287 static void replace_pop_native_frame(executionstate_t *es,
2289 stackframeinfo_t *sfi)
2291 sourceframe_t *frame;
2297 frame = replace_new_sourceframe(ss);
2301 /* remember pc and size of native frame */
2303 frame->nativepc = es->pc;
2304 frame->nativeframesize = (es->sp != 0) ? (((uintptr_t) sfi->sp) - ((uintptr_t) es->sp)) : 0;
2305 assert(frame->nativeframesize >= 0);
2307 /* remember values of saved registers */
2310 for (i=0; i<INT_REG_CNT; ++i) {
2311 if (nregdescint[i] == REG_SAV)
2312 frame->nativesavint[j++] = es->intregs[i];
2316 for (i=0; i<FLT_REG_CNT; ++i) {
2317 if (nregdescfloat[i] == REG_SAV)
2318 frame->nativesavflt[j++] = es->fltregs[i];
2321 #if defined(HAS_ADDRESS_REGISTER_FILE)
2323 for (i=0; i<ADR_REG_CNT; ++i) {
2324 if (nregdescadr[i] == REG_SAV)
2325 frame->nativesavadr[j++] = es->adrregs[i];
2329 /* restore saved registers */
2331 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2333 for (i=0; i<INT_REG_CNT; ++i) {
2334 if (nregdescint[i] == REG_SAV)
2335 es->intregs[i] = sfi->intregs[j++];
2338 /* XXX we don't have them, yet, in the sfi, so clear them */
2340 for (i=0; i<INT_REG_CNT; ++i) {
2341 if (nregdescint[i] == REG_SAV)
2346 /* XXX we don't have float registers in the sfi, so clear them */
2348 for (i=0; i<FLT_REG_CNT; ++i) {
2349 if (nregdescfloat[i] == REG_SAV)
2350 es->fltregs[i] = 0.0;
2353 #if defined(HAS_ADDRESS_REGISTER_FILE)
2354 # if defined(ENABLE_GC_CACAO)
2356 for (i=0; i<ADR_REG_CNT; ++i) {
2357 if (nregdescadr[i] == REG_SAV)
2358 es->adrregs[i] = sfi->adrregs[j++];
2361 for (i=0; i<ADR_REG_CNT; ++i) {
2362 if (nregdescadr[i] == REG_SAV)
2368 /* restore codeinfo of the native stub */
2370 code = code_get_codeinfo_for_pv(sfi->pv);
2372 /* restore sp, pv, pc and codeinfo of the parent method */
2374 /* XXX michi: use this instead:
2375 es->sp = sfi->sp + code->stackframesize; */
2376 es->sp = (uint8_t*) (((uintptr_t) sfi->sp) + (*(s4 *) (((uintptr_t) sfi->pv) + FrameSize)));
2377 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2378 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
2380 es->pv = (uint8_t*) md_codegen_get_pv_from_pc(sfi->ra);
2381 es->pc = (uint8_t*) (((uintptr_t) ((sfi->xpc) ? sfi->xpc : sfi->ra)) - 1);
2382 es->code = code_get_codeinfo_for_pv(es->pv);
2386 /* replace_push_native_frame ***************************************************
2388 Rebuild a native frame onto the execution state and remove its source frame.
2390 Note: The native frame is "rebuild" by setting fields like PC and stack
2391 pointer in the execution state accordingly. Values in the
2392 stackframeinfo may be modified, but the actual stack frame of the
2393 native code is not touched.
2396 es...............current execution state
2397 ss...............the current source state
2400 es...............execution state after re-rolling the native frame
2401 ss...............the native source frame is removed
2403 *******************************************************************************/
2405 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2407 sourceframe_t *frame;
2413 DOLOG( printf("pushing native frame\n"); );
2415 /* remove the frame from the source state */
2419 assert(REPLACE_IS_NATIVE_FRAME(frame));
2421 ss->frames = frame->down;
2423 /* skip sp for the native stub */
2425 es->sp -= (*(s4 *) (((uintptr_t) frame->sfi->pv) + FrameSize));
2426 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2427 es->sp -= SIZE_OF_STACKSLOT; /* skip return address */
2430 /* assert that the native frame has not moved */
2432 assert(es->sp == frame->sfi->sp);
2434 /* update saved registers in the stackframeinfo */
2436 #if defined(ENABLE_GC_CACAO)
2438 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2439 for (i=0; i<INT_REG_CNT; ++i) {
2440 if (nregdescint[i] == REG_SAV)
2441 frame->sfi->intregs[j++] = es->intregs[i];
2444 for (i=0; i<ADR_REG_CNT; ++i) {
2445 if (nregdescadr[i] == REG_SAV)
2446 frame->sfi->adrregs[j++] = es->adrregs[i];
2450 /* XXX leave float registers untouched here */
2453 /* restore saved registers */
2456 for (i=0; i<INT_REG_CNT; ++i) {
2457 if (nregdescint[i] == REG_SAV)
2458 es->intregs[i] = frame->nativesavint[j++];
2462 for (i=0; i<FLT_REG_CNT; ++i) {
2463 if (nregdescfloat[i] == REG_SAV)
2464 es->fltregs[i] = frame->nativesavflt[j++];
2467 #if defined(HAS_ADDRESS_REGISTER_FILE)
2469 for (i=0; i<ADR_REG_CNT; ++i) {
2470 if (nregdescadr[i] == REG_SAV)
2471 es->adrregs[i] = frame->nativesavadr[j++];
2475 /* skip the native frame on the machine stack */
2477 es->sp -= frame->nativeframesize;
2479 /* set the pc the next frame must return to */
2481 es->pc = frame->nativepc;
2485 /* replace_recover_source_state ************************************************
2487 Recover the source state from the given replacement point and execution
2491 rp...............replacement point that has been reached, if any
2492 sfi..............stackframeinfo, if called from native code
2493 es...............execution state at the replacement point rp
2498 *******************************************************************************/
2500 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2501 stackframeinfo_t *sfi,
2502 executionstate_t *es)
2507 #if defined(REPLACE_STATISTICS)
2511 /* create the source frame structure in dump memory */
2513 ss = (sourcestate_t*) DumpMemory::allocate(sizeof(sourcestate_t));
2516 /* each iteration of the loop recovers one source frame */
2523 DOLOG( executionstate_println(es); );
2525 /* if we are not at a replacement point, it is a native frame */
2528 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2531 replace_pop_native_frame(es, ss, sfi);
2534 if (es->code == NULL)
2537 goto after_machine_frame;
2540 /* read the values for this source frame from the execution state */
2542 DOLOG( printf("recovering source state for%s:\n",
2543 (ss->frames == NULL) ? " TOPFRAME" : "");
2544 replace_replacement_point_println(rp, 1); );
2546 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2548 #if defined(ENABLE_VMLOG)
2549 vmlog_cacao_unrol_method(ss->frames->method);
2552 #if defined(REPLACE_STATISTICS)
2553 REPLACE_COUNT(stat_frames);
2555 replace_statistics_source_frame(ss->frames);
2558 /* in locked areas (below native frames), identity map the frame */
2561 ss->frames->torp = ss->frames->fromrp;
2562 ss->frames->tocode = ss->frames->fromcode;
2565 /* unroll to the next (outer) frame */
2568 /* this frame is in inlined code */
2570 DOLOG( printf("INLINED!\n"); );
2574 assert(rp->type == RPLPOINT_TYPE_INLINE);
2575 REPLACE_COUNT(stat_unroll_inline);
2578 /* this frame had been called at machine-level. pop it. */
2580 DOLOG( printf("UNWIND\n"); );
2582 ra = replace_pop_activation_record(es, ss->frames);
2584 DOLOG( printf("REACHED NATIVE CODE\n"); );
2588 #if !defined(ENABLE_GC_CACAO)
2589 break; /* XXX remove to activate native frames */
2594 /* find the replacement point at the call site */
2596 after_machine_frame:
2597 rp = replace_find_replacement_point_for_pc(es->code, es->pc, 0);
2600 vm_abort("could not find replacement point while unrolling call");
2602 DOLOG( printf("found replacement point.\n");
2603 replace_replacement_point_println(rp, 1); );
2605 assert(rp->type == RPLPOINT_TYPE_CALL);
2606 REPLACE_COUNT(stat_unroll_call);
2608 } /* end loop over source frames */
2610 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2616 /* replace_map_source_state ****************************************************
2618 Map each source frame in the given source state to a target replacement
2619 point and compilation unit. If no valid code is available for a source
2620 frame, it is (re)compiled.
2623 ss...............the source state
2626 ss...............the source state, modified: The `torp` and `tocode`
2627 fields of each source frame are set.
2630 true.............everything went ok
2631 false............an exception has been thrown
2633 *******************************************************************************/
2635 static bool replace_map_source_state(sourcestate_t *ss)
2637 sourceframe_t *frame;
2640 rplpoint *parent; /* parent of inlined rplpoint */
2641 #if defined(REPLACE_STATISTICS)
2648 /* iterate over the source frames from outermost to innermost */
2650 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2652 /* XXX skip native frames */
2654 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2659 /* map frames which are not already mapped */
2661 if (frame->tocode) {
2662 code = frame->tocode;
2667 assert(frame->torp == NULL);
2669 if (parent == NULL) {
2670 /* find code for this frame */
2672 #if defined(REPLACE_STATISTICS)
2673 oldcode = frame->method->code;
2675 /* request optimization of hot methods and their callers */
2677 if (frame->method->hitcountdown < 0
2678 || (frame->down && frame->down->method->hitcountdown < 0))
2679 jit_request_optimization(frame->method);
2681 code = jit_get_current_code(frame->method);
2684 return false; /* exception */
2686 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2691 /* map this frame */
2693 rp = replace_find_replacement_point(code, frame, parent);
2695 frame->tocode = code;
2699 if (rp->type == RPLPOINT_TYPE_CALL) {
2712 /* replace_map_source_state_identity *******************************************
2714 Map each source frame in the given source state to the same replacement
2715 point and compilation unit it was derived from. This is mainly used for
2719 ss...............the source state
2722 ss...............the source state, modified: The `torp` and `tocode`
2723 fields of each source frame are set.
2725 *******************************************************************************/
2727 #if defined(ENABLE_GC_CACAO)
2728 static void replace_map_source_state_identity(sourcestate_t *ss)
2730 sourceframe_t *frame;
2732 /* iterate over the source frames from outermost to innermost */
2734 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2736 /* skip native frames */
2738 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2742 /* map frames using the identity mapping */
2744 if (frame->tocode) {
2745 assert(frame->tocode == frame->fromcode);
2746 assert(frame->torp == frame->fromrp);
2748 assert(frame->tocode == NULL);
2749 assert(frame->torp == NULL);
2750 frame->tocode = frame->fromcode;
2751 frame->torp = frame->fromrp;
2758 /* replace_build_execution_state ***********************************************
2760 Build an execution state for the given (mapped) source state.
2762 !!! CAUTION: This function rewrites the machine stack !!!
2764 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2767 ss...............the source state. Must have been mapped by
2768 replace_map_source_state before.
2769 es...............the base execution state on which to build
2772 *es..............the new execution state
2774 *******************************************************************************/
2776 static void replace_build_execution_state(sourcestate_t *ss,
2777 executionstate_t *es)
2780 sourceframe_t *prevframe;
2787 while (ss->frames) {
2789 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2790 prevframe = ss->frames;
2791 replace_push_native_frame(es, ss);
2797 if (parent == NULL) {
2798 /* create a machine-level stack frame */
2800 DOLOG( printf("pushing activation record for:\n");
2801 if (rp) replace_replacement_point_println(rp, 1);
2802 else printf("\tfirst frame\n"); );
2804 replace_push_activation_record(es, rp, prevframe, ss->frames);
2806 DOLOG( executionstate_println(es); );
2809 rp = ss->frames->torp;
2812 DOLOG( printf("creating execution state for%s:\n",
2813 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2814 replace_replacement_point_println(ss->frames->fromrp, 1);
2815 replace_replacement_point_println(rp, 1); );
2817 es->code = ss->frames->tocode;
2818 prevframe = ss->frames;
2820 #if defined(ENABLE_VMLOG)
2821 vmlog_cacao_rerol_method(ss->frames->method);
2824 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2826 DOLOG( executionstate_println(es); );
2828 if (rp->type == RPLPOINT_TYPE_CALL) {
2839 /* replace_me ******************************************************************
2841 This function is called by the signal handler when a thread reaches
2842 a replacement point. `replace_me` must map the execution state to the
2843 target replacement point and let execution continue there.
2845 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2848 rp...............replacement point that has been reached
2849 es...............execution state read by signal handler
2851 *******************************************************************************/
2853 static void replace_me(rplpoint *rp, executionstate_t *es)
2855 stackframeinfo_t *sfi;
2857 sourceframe_t *frame;
2860 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2861 threadobject *thread;
2864 origcode = es->code;
2867 #if defined(ENABLE_TLH)
2868 /*printf("Replacing in %s/%s\n", rp->method->clazz->name->text, rp->method->name->text);*/
2871 /*if (strcmp(rp->method->clazz->name->text, "antlr/AlternativeElement") == 0 && strcmp(rp->method->name->text, "getAutoGenType") ==0) opt_TraceReplacement = 2; else opt_TraceReplacement = 0;*/
2873 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2874 stat_replacements, (void*)THREADOBJECT,
2876 method_println(es->code->m); );
2878 DOLOG( replace_replacement_point_println(rp, 1); );
2880 REPLACE_COUNT(stat_replacements);
2882 // Create new dump memory area.
2885 /* Get the stackframeinfo for the current thread. */
2887 sfi = threads_get_current_stackframeinfo();
2889 /* recover source state */
2891 ss = replace_recover_source_state(rp, sfi, es);
2893 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2894 /* if there is a collection pending, we assume the replacement point should
2895 suspend this thread */
2899 thread = THREADOBJECT;
2901 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2903 /* map the sourcestate using the identity mapping */
2904 replace_map_source_state_identity(ss);
2906 /* since we enter the same method again, we turn off rps now */
2907 /* XXX michi: can we really do this? what if the rp was active before
2908 we activated it for the gc? */
2909 replace_deactivate_replacement_points(origcode);
2911 /* remember executionstate and sourcestate for this thread */
2912 GC_EXECUTIONSTATE = es;
2913 GC_SOURCESTATE = ss;
2915 /* really suspend this thread now (PC = 0) */
2916 threads_suspend_ack(NULL, NULL);
2918 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2921 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2923 /* map the source state */
2925 if (!replace_map_source_state(ss))
2926 vm_abort("exception during method replacement");
2928 DOLOG( replace_sourcestate_println(ss); );
2930 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2932 #if !defined(NDEBUG)
2933 /* avoid infinite loops by self-replacement, only if not in testing mode */
2935 if (!opt_TestReplacement) {
2938 frame = frame->down;
2940 if (frame->torp == origrp) {
2942 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2944 replace_deactivate_replacement_points(origcode);
2949 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2953 /* build the new execution state */
2955 replace_build_execution_state(ss, es);
2957 #if !defined(NDEBUG)
2958 /* continue execution after patched machine code, if testing mode enabled */
2960 if (opt_TestReplacement)
2961 es->pc += REPLACEMENT_PATCH_SIZE;
2966 /* replace_me_wrapper **********************************************************
2968 This function is called by the signal handler. It determines if there
2969 is an active replacement point pending at the given PC and returns
2972 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2975 pc...............the program counter that triggered the replacement.
2976 context..........the context (machine state) to which the
2977 replacement should be applied.
2980 context..........the context after replacement finished.
2983 true.............replacement done, everything went ok
2984 false............no replacement done, context unchanged
2986 *******************************************************************************/
2988 bool replace_me_wrapper(u1 *pc, void *context)
2992 executionstate_t es;
2993 #if defined(ENABLE_RT_TIMING)
2994 struct timespec time_start, time_end;
2997 /* search the codeinfo for the given PC */
2999 code = code_find_codeinfo_for_pc(pc);
3002 /* search for a replacement point at the given PC */
3004 rp = replace_find_replacement_point_for_pc(code, pc, (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN));
3006 /* check if the replacement point belongs to given PC and is active */
3008 if ((rp != NULL) && (rp->pc == pc)
3009 && (rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))) {
3011 DOLOG( printf("valid replacement point\n"); );
3013 #if !defined(NDEBUG)
3014 executionstate_sanity_check(context);
3017 /* set codeinfo pointer in execution state */
3021 /* read execution state from current context */
3023 md_executionstate_read(&es, context);
3025 DOLOG( printf("REPLACEMENT READ: ");
3026 executionstate_println(&es); );
3028 /* do the actual replacement */
3030 #if defined(ENABLE_RT_TIMING)
3031 RT_TIMING_GET_TIME(time_start);
3034 replace_me(rp, &es);
3036 #if defined(ENABLE_RT_TIMING)
3037 RT_TIMING_GET_TIME(time_end);
3038 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_REPLACE);
3041 /* write execution state to current context */
3043 md_executionstate_write(&es, context);
3045 DOLOG( printf("REPLACEMENT WRITE: ");
3046 executionstate_println(&es); );
3048 /* new code is entered after returning */
3050 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
3058 /******************************************************************************/
3059 /* NOTE: Stuff specific to the exact GC is below. */
3060 /******************************************************************************/
3062 #if defined(ENABLE_GC_CACAO)
3063 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
3065 stackframeinfo_t *sfi;
3066 executionstate_t *es;
3069 /* Get the stackframeinfo of this thread. */
3071 assert(thread == THREADOBJECT);
3073 sfi = threads_get_current_stackframeinfo();
3075 /* create the execution state */
3076 es = (executionstate_t*) DumpMemory::allocate(sizeof(executionstate_t));
3079 es->pv = 0; /* since we are in a native, PV is invalid! */
3080 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
3082 /* we assume we are in a native (no replacement point)! */
3083 ss = replace_recover_source_state(NULL, sfi, es);
3085 /* map the sourcestate using the identity mapping */
3086 replace_map_source_state_identity(ss);
3088 /* remember executionstate and sourcestate for this thread */
3089 GC_EXECUTIONSTATE = es;
3090 GC_SOURCESTATE = ss;
3094 #if defined(ENABLE_GC_CACAO)
3095 void replace_gc_into_native(threadobject *thread)
3097 executionstate_t *es;
3100 /* get the executionstate and sourcestate for the given thread */
3101 es = GC_EXECUTIONSTATE;
3102 ss = GC_SOURCESTATE;
3104 /* rebuild the stack of the given thread */
3105 replace_build_execution_state(ss, es);
3110 /******************************************************************************/
3111 /* NOTE: No important code below. */
3112 /******************************************************************************/
3115 /* statistics *****************************************************************/
3117 #if defined(REPLACE_STATISTICS)
3118 static void print_freq(FILE *file,int *array,int limit)
3123 for (i=0; i<limit; ++i)
3125 sum += array[limit];
3126 for (i=0; i<limit; ++i) {
3128 fprintf(file," %3d: %8d (cum %3d%%)\n",
3129 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3131 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3133 #endif /* defined(REPLACE_STATISTICS) */
3136 #if defined(REPLACE_STATISTICS)
3138 #define REPLACE_PRINT_DIST(name, array) \
3139 printf(" " name " distribution:\n"); \
3140 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3142 void replace_print_statistics(void)
3144 printf("replacement statistics:\n");
3145 printf(" # of replacements: %d\n", stat_replacements);
3146 printf(" # of frames: %d\n", stat_frames);
3147 printf(" # of recompilations: %d\n", stat_recompile);
3148 printf(" patched static calls:%d\n", stat_staticpatch);
3149 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3150 printf(" unrolled calls: %d\n", stat_unroll_call);
3151 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3152 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3153 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3154 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3155 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3156 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3157 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3158 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3159 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3160 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3162 printf(" # of methods: %d\n", stat_methods);
3163 printf(" # of replacement points: %d\n", stat_rploints);
3164 printf(" # of regallocs: %d\n", stat_regallocs);
3165 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3166 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3167 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3171 #endif /* defined(REPLACE_STATISTICS) */
3174 #if defined(REPLACE_STATISTICS)
3175 static void replace_statistics_source_frame(sourceframe_t *frame)
3184 for (i=0; i<frame->javalocalcount; ++i) {
3185 switch (frame->javalocaltype[i]) {
3186 case TYPE_ADR: adr++; break;
3187 case TYPE_RET: ret++; break;
3188 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3189 case TYPE_VOID: vd++; break;
3194 REPLACE_COUNT_DIST(stat_dist_locals, n);
3195 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3196 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3197 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3198 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3199 adr = ret = prim = n = 0;
3200 for (i=0; i<frame->javastackdepth; ++i) {
3201 switch (frame->javastacktype[i]) {
3202 case TYPE_ADR: adr++; break;
3203 case TYPE_RET: ret++; break;
3204 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3208 REPLACE_COUNT_DIST(stat_dist_stack, n);
3209 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3210 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3211 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3213 #endif /* defined(REPLACE_STATISTICS) */
3216 /* debugging helpers **********************************************************/
3218 /* replace_replacement_point_println *******************************************
3220 Print replacement point info.
3223 rp...............the replacement point to print
3225 *******************************************************************************/
3227 #if !defined(NDEBUG)
3229 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3231 static const char *replace_type_str[] = {
3241 void replace_replacement_point_println(rplpoint *rp, int depth)
3247 printf("(rplpoint *)NULL\n");
3251 for (j=0; j<depth; ++j)
3254 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3255 rp->id, (void*)rp,rp->pc,rp->callsize,
3256 replace_type_str[rp->type]);
3257 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3259 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3260 printf(" COUNTDOWN");
3261 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3263 printf(" parent:%p\n", (void*)rp->parent);
3264 for (j=0; j<depth; ++j)
3266 printf("ra:%d = [", rp->regalloccount);
3268 for (j=0; j<rp->regalloccount; ++j) {
3271 index = rp->regalloc[j].index;
3273 case RPLALLOC_STACK: printf("S"); break;
3274 case RPLALLOC_PARAM: printf("P"); break;
3275 case RPLALLOC_SYNC : printf("Y"); break;
3276 default: printf("%d", index);
3278 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3279 if (rp->regalloc[j].type == TYPE_RET) {
3280 printf("ret(L%03d)", rp->regalloc[j].regoff);
3283 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3288 for (j=0; j<depth; ++j)
3291 method_print(rp->method);
3295 #endif /* !defined(NDEBUG) */
3298 /* replace_show_replacement_points *********************************************
3300 Print replacement point info.
3303 code.............codeinfo whose replacement points should be printed.
3305 *******************************************************************************/
3307 #if !defined(NDEBUG)
3308 void replace_show_replacement_points(codeinfo *code)
3316 printf("(codeinfo *)NULL\n");
3320 printf("\treplacement points: %d\n",code->rplpointcount);
3322 printf("\ttotal allocations : %d\n",code->regalloccount);
3323 printf("\tsaved int regs : %d\n",code->savedintcount);
3324 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3325 #if defined(HAS_ADDRESS_REGISTER_FILE)
3326 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3328 printf("\tmemuse : %d\n",code->memuse);
3332 for (i=0; i<code->rplpointcount; ++i) {
3333 rp = code->rplpoints + i;
3336 parent = rp->parent;
3339 parent = parent->parent;
3341 replace_replacement_point_println(rp, depth);
3347 #if !defined(NDEBUG)
3348 static void java_value_print(s4 type, replace_val_t value)
3353 printf("%016llx",(unsigned long long) value.l);
3355 if (type < 0 || type > TYPE_RET)
3356 printf(" <INVALID TYPE:%d>", type);
3358 printf(" %s", show_jit_type_names[type]);
3360 if (type == TYPE_ADR && value.a != NULL) {
3363 utf_display_printable_ascii_classname(obj->vftbl->clazz->name);
3365 if (obj->vftbl->clazz == class_java_lang_String) {
3367 u = javastring_toutf(obj, false);
3368 utf_display_printable_ascii(u);
3372 else if (type == TYPE_INT) {
3373 printf(" %ld", (long) value.i);
3375 else if (type == TYPE_LNG) {
3376 printf(" %lld", (long long) value.l);
3378 else if (type == TYPE_FLT) {
3379 printf(" %f", value.f);
3381 else if (type == TYPE_DBL) {
3382 printf(" %f", value.d);
3385 #endif /* !defined(NDEBUG) */
3388 #if !defined(NDEBUG)
3389 void replace_source_frame_println(sourceframe_t *frame)
3394 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3395 printf("\tNATIVE\n");
3396 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3397 printf("\tnativepc: %p\n", frame->nativepc);
3398 printf("\tframesize: %d\n", frame->nativeframesize);
3401 for (i=0; i<INT_REG_CNT; ++i) {
3402 if (nregdescint[i] == REG_SAV)
3403 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3407 for (i=0; i<FLT_REG_CNT; ++i) {
3408 if (nregdescfloat[i] == REG_SAV)
3409 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3417 method_println(frame->method);
3418 printf("\tid: %d\n", frame->id);
3419 printf("\ttype: %s\n", replace_type_str[frame->type]);
3422 if (frame->instance.a) {
3423 printf("\tinstance: ");
3424 java_value_print(TYPE_ADR, frame->instance);
3428 if (frame->javalocalcount) {
3429 printf("\tlocals (%d):\n",frame->javalocalcount);
3430 for (i=0; i<frame->javalocalcount; ++i) {
3431 t = frame->javalocaltype[i];
3432 if (t == TYPE_VOID) {
3433 printf("\tlocal[ %2d] = void\n",i);
3436 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3437 java_value_print(t, frame->javalocals[i]);
3444 if (frame->javastackdepth) {
3445 printf("\tstack (depth %d):\n",frame->javastackdepth);
3446 for (i=0; i<frame->javastackdepth; ++i) {
3447 t = frame->javastacktype[i];
3448 if (t == TYPE_VOID) {
3449 printf("\tstack[%2d] = void", i);
3452 printf("\tstack[%2d] = ",i);
3453 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3460 if (frame->syncslotcount) {
3461 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3462 for (i=0; i<frame->syncslotcount; ++i) {
3463 printf("\tslot[%2d] = %016llx\n",i,(unsigned long long) frame->syncslots[i].p);
3468 if (frame->fromcode) {
3469 printf("\tfrom %p ", (void*)frame->fromcode);
3470 method_println(frame->fromcode->m);
3472 if (frame->tocode) {
3473 printf("\tto %p ", (void*)frame->tocode);
3474 method_println(frame->tocode->m);
3477 if (frame->fromrp) {
3478 printf("\tfrom replacement point:\n");
3479 replace_replacement_point_println(frame->fromrp, 2);
3482 printf("\tto replacement point:\n");
3483 replace_replacement_point_println(frame->torp, 2);
3488 #endif /* !defined(NDEBUG) */
3491 /* replace_sourcestate_println *************************************************
3496 ss...............the source state to print
3498 *******************************************************************************/
3500 #if !defined(NDEBUG)
3501 void replace_sourcestate_println(sourcestate_t *ss)
3504 sourceframe_t *frame;
3507 printf("(sourcestate_t *)NULL\n");
3511 printf("sourcestate_t:\n");
3513 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3514 printf(" frame %d:\n", i);
3515 replace_source_frame_println(frame);
3521 /* replace_sourcestate_println_short *******************************************
3523 Print a compact representation of the given source state.
3526 ss...............the source state to print
3528 *******************************************************************************/
3530 #if !defined(NDEBUG)
3531 void replace_sourcestate_println_short(sourcestate_t *ss)
3533 sourceframe_t *frame;
3535 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3538 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3539 printf("NATIVE (pc %p size %d) ",
3540 (void*)frame->nativepc, frame->nativeframesize);
3541 replace_stackframeinfo_println(frame->sfi);
3546 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3549 printf("%s", replace_type_str[frame->fromrp->type]);
3551 if (frame->torp && frame->torp->type != frame->fromrp->type)
3552 printf("->%s", replace_type_str[frame->torp->type]);
3554 if (frame->tocode != frame->fromcode)
3555 printf(" (%p->%p/%d) ",
3556 (void*) frame->fromcode, (void*) frame->tocode,
3559 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3561 method_println(frame->method);
3566 #if !defined(NDEBUG)
3567 static void replace_stackframeinfo_println(stackframeinfo_t *sfi)
3569 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3570 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3571 (void*)sfi->ra, (void*)sfi->xpc);
3574 method_println(sfi->code->m);
3582 * These are local overrides for various environment variables in Emacs.
3583 * Please do not remove this and leave it at the end of the file, where
3584 * Emacs will automagically detect them.
3585 * ---------------------------------------------------------------------
3588 * indent-tabs-mode: t
3592 * vim:noexpandtab:sw=4:ts=4: