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/memory.h"
42 #include "threads/thread.hpp"
44 #include "toolbox/logging.h"
46 #include "vm/classcache.h"
47 #include "vm/globals.hpp"
48 #include "vm/options.h"
49 #include "vm/string.hpp"
51 #if defined(ENABLE_RT_TIMING)
52 # include "vm/rt-timing.h"
55 #include "vm/jit/abi.h"
56 #include "vm/jit/asmpart.h"
57 #include "vm/jit/disass.h"
58 #include "vm/jit/executionstate.h"
59 #include "vm/jit/jit.hpp"
60 #include "vm/jit/methodheader.h"
61 #include "vm/jit/replace.hpp"
62 #include "vm/jit/show.h"
63 #include "vm/jit/stack.h"
66 #define REPLACE_PATCH_DYNAMIC_CALL
67 /*#define REPLACE_PATCH_ALL*/
69 #if defined(ENABLE_VMLOG)
70 #include <vmlog_cacao.h>
73 /*** architecture-dependent configuration *************************************/
75 /* first unset the macros (default) */
76 #undef REPLACE_RA_BETWEEN_FRAMES
77 #undef REPLACE_RA_TOP_OF_FRAME
78 #undef REPLACE_RA_LINKAGE_AREA
79 #undef REPLACE_LEAFMETHODS_RA_REGISTER
81 /* i386, x86_64 and m68k */
82 #if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
83 #define REPLACE_RA_BETWEEN_FRAMES
85 #elif defined(__ALPHA__)
86 #define REPLACE_RA_TOP_OF_FRAME
87 #define REPLACE_LEAFMETHODS_RA_REGISTER
89 #elif defined(__POWERPC__)
90 #define REPLACE_RA_LINKAGE_AREA
91 #define REPLACE_LEAFMETHODS_RA_REGISTER
93 #elif defined(__S390__)
94 #define REPLACE_RA_TOP_OF_FRAME
98 /*** configuration of native stack slot size **********************************/
100 /* XXX this should be in md-abi.h files, probably */
102 #if defined(HAS_4BYTE_STACKSLOT)
103 #define SIZE_OF_STACKSLOT 4
104 #define STACK_SLOTS_PER_FLOAT 2
105 typedef u4 stackslot_t;
107 #define SIZE_OF_STACKSLOT 8
108 #define STACK_SLOTS_PER_FLOAT 1
109 typedef u8 stackslot_t;
113 /*** debugging ****************************************************************/
116 static void java_value_print(s4 type, replace_val_t value);
117 static void replace_stackframeinfo_println(stackframeinfo_t *sfi);
121 #define DOLOG(code) do{ if (opt_TraceReplacement > 1) { code; } } while(0)
122 #define DOLOG_SHORT(code) do{ if (opt_TraceReplacement > 0) { code; } } while(0)
125 #define DOLOG_SHORT(code)
129 /*** statistics ***************************************************************/
131 #define REPLACE_STATISTICS
133 #if defined(REPLACE_STATISTICS)
135 static int stat_replacements = 0;
136 static int stat_frames = 0;
137 static int stat_recompile = 0;
138 static int stat_staticpatch = 0;
139 static int stat_unroll_inline = 0;
140 static int stat_unroll_call = 0;
141 static int stat_dist_frames[20] = { 0 };
142 static int stat_dist_locals[20] = { 0 };
143 static int stat_dist_locals_adr[10] = { 0 };
144 static int stat_dist_locals_prim[10] = { 0 };
145 static int stat_dist_locals_ret[10] = { 0 };
146 static int stat_dist_locals_void[10] = { 0 };
147 static int stat_dist_stack[10] = { 0 };
148 static int stat_dist_stack_adr[10] = { 0 };
149 static int stat_dist_stack_prim[10] = { 0 };
150 static int stat_dist_stack_ret[10] = { 0 };
151 static int stat_methods = 0;
152 static int stat_rploints = 0;
153 static int stat_regallocs = 0;
154 static int stat_dist_method_rplpoints[20] = { 0 };
156 #define REPLACE_COUNT(cnt) (cnt)++
157 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
158 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
160 #define REPLACE_COUNT_DIST(array, val) \
162 int limit = (sizeof(array) / sizeof(int)) - 1; \
163 if ((val) < (limit)) (array)[val]++; \
164 else (array)[limit]++; \
167 static void replace_statistics_source_frame(sourceframe_t *frame);
171 #define REPLACE_COUNT(cnt)
172 #define REPLACE_COUNT_IF(cnt, cond)
173 #define REPLACE_COUNT_INC(cnt, inc)
174 #define REPLACE_COUNT_DIST(array, val)
176 #endif /* defined(REPLACE_STATISTICS) */
179 /*** constants used internally ************************************************/
181 #define TOP_IS_NORMAL 0
182 #define TOP_IS_ON_STACK 1
183 #define TOP_IS_IN_ITMP1 2
184 #define TOP_IS_VOID 3
187 /******************************************************************************/
188 /* PART I: Creating / freeing replacement points */
189 /******************************************************************************/
192 /* replace_create_replacement_point ********************************************
194 Create a replacement point.
197 jd...............current jitdata
198 iinfo............inlining info for the current position
199 rp...............pre-allocated (uninitialized) rplpoint
200 type.............RPLPOINT_TYPE constant
201 iptr.............current instruction
202 *pra.............current rplalloc pointer
203 javalocals.......the javalocals at the current point
204 stackvars........the stack variables at the current point
205 stackdepth.......the stack depth at the current point
206 paramcount.......number of parameters at the start of stackvars
209 *rpa.............points to the next free rplalloc
211 *******************************************************************************/
213 static void replace_create_replacement_point(jitdata *jd,
214 insinfo_inline *iinfo,
231 REPLACE_COUNT(stat_rploints);
233 rp->method = (iinfo) ? iinfo->method : jd->m;
234 rp->pc = NULL; /* set by codegen */
235 rp->callsize = 0; /* set by codegen */
239 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
241 /* XXX unify these two fields */
242 rp->parent = (iinfo) ? iinfo->rp : NULL;
244 /* store local allocation info of javalocals */
247 for (i = 0; i < rp->method->maxlocals; ++i) {
248 index = javalocals[i];
255 ra->flags = v->flags & (INMEMORY);
256 ra->regoff = v->vv.regoff;
260 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
268 /* store allocation info of java stack vars */
270 for (i = 0; i < stackdepth; ++i) {
271 v = VAR(stackvars[i]);
272 ra->flags = v->flags & (INMEMORY);
273 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
275 /* XXX how to handle locals on the stack containing returnAddresses? */
276 if (v->type == TYPE_RET) {
277 assert(stackvars[i] >= jd->localcount);
278 ra->regoff = v->vv.retaddr->nr;
281 ra->regoff = v->vv.regoff;
285 /* total number of allocations */
287 rp->regalloccount = ra - rp->regalloc;
293 /* replace_create_inline_start_replacement_point *******************************
295 Create an INLINE_START replacement point.
298 jd...............current jitdata
299 rp...............pre-allocated (uninitialized) rplpoint
300 iptr.............current instruction
301 *pra.............current rplalloc pointer
302 javalocals.......the javalocals at the current point
305 *rpa.............points to the next free rplalloc
308 the insinfo_inline * for the following inlined body
310 *******************************************************************************/
312 static insinfo_inline * replace_create_inline_start_replacement_point(
319 insinfo_inline *calleeinfo;
322 calleeinfo = iptr->sx.s23.s3.inlineinfo;
326 replace_create_replacement_point(jd, calleeinfo->parent, rp,
327 RPLPOINT_TYPE_INLINE, iptr, pra,
329 calleeinfo->stackvars, calleeinfo->stackvarscount,
330 calleeinfo->paramcount);
332 if (calleeinfo->synclocal != UNUSED) {
334 ra->index = RPLALLOC_SYNC;
335 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
336 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
346 /* replace_create_replacement_points *******************************************
348 Create the replacement points for the given code.
351 jd...............current jitdata, must not have any replacement points
354 code->rplpoints.......set to the list of replacement points
355 code->rplpointcount...number of replacement points
356 code->regalloc........list of allocation info
357 code->regalloccount...total length of allocation info list
358 code->globalcount.....number of global allocations at the
359 start of code->regalloc
362 true.............everything ok
363 false............an exception has been thrown
365 *******************************************************************************/
367 #define CLEAR_javalocals(array, method) \
369 for (i=0; i<(method)->maxlocals; ++i) \
370 (array)[i] = UNUSED; \
373 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
375 if ((array) != NULL) \
376 MCOPY((dest), (array), s4, (method)->maxlocals); \
378 CLEAR_javalocals((dest), (method)); \
381 #define COUNT_javalocals(array, method, counter) \
383 for (i=0; i<(method)->maxlocals; ++i) \
384 if ((array)[i] != UNUSED) \
388 bool replace_create_replacement_points(jitdata *jd)
406 insinfo_inline *iinfo;
409 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
413 REPLACE_COUNT(stat_methods);
415 /* get required compiler data */
420 /* assert that we wont overwrite already allocated data */
424 assert(code->rplpoints == NULL);
425 assert(code->rplpointcount == 0);
426 assert(code->regalloc == NULL);
427 assert(code->regalloccount == 0);
428 assert(code->globalcount == 0);
432 /* in instance methods, we may need a rplpoint at the method entry */
434 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
435 if (!(m->flags & ACC_STATIC)) {
436 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
442 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
444 /* iterate over the basic block list to find replacement points */
449 javalocals = DMNEW(s4, jd->maxlocals);
451 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
455 if (bptr->flags < BBFINISHED)
458 /* get info about this block */
461 iinfo = bptr->inlineinfo;
463 /* initialize javalocals at the start of this block */
465 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
467 /* iterate over the instructions */
470 iend = iptr + bptr->icount;
474 for (; iptr != iend; ++iptr) {
476 #if defined(ENABLE_GC_CACAO)
478 md = iptr->sx.s23.s3.bte->md;
480 COUNT_javalocals(javalocals, m, alloccount);
481 alloccount += iptr->s1.argcount;
483 alloccount -= iinfo->throughcount;
487 case ICMD_INVOKESTATIC:
488 case ICMD_INVOKESPECIAL:
489 case ICMD_INVOKEVIRTUAL:
490 case ICMD_INVOKEINTERFACE:
491 INSTRUCTION_GET_METHODDESC(iptr, md);
493 COUNT_javalocals(javalocals, m, alloccount);
494 alloccount += iptr->s1.argcount;
496 alloccount -= iinfo->throughcount;
504 stack_javalocals_store(iptr, javalocals);
518 case ICMD_INLINE_START:
519 iinfo = iptr->sx.s23.s3.inlineinfo;
522 COUNT_javalocals(javalocals, m, alloccount);
523 alloccount += iinfo->stackvarscount;
524 if (iinfo->synclocal != UNUSED)
528 /* javalocals may be set at next block start, or now */
529 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
532 case ICMD_INLINE_BODY:
533 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
535 jl = iinfo->javalocals_start;
537 /* get the javalocals from the following block start */
539 jl = bptr->next->javalocals;
542 COUNT_javalocals(jl, m, alloccount);
545 case ICMD_INLINE_END:
546 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
547 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
548 iinfo = iptr->sx.s23.s3.inlineinfo;
550 if (iinfo->javalocals_end)
551 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
552 iinfo = iinfo->parent;
556 if (iptr == bptr->iinstr)
558 } /* end instruction loop */
560 /* create replacement points at targets of backward branches */
561 /* We only need the replacement point there, if there is no */
562 /* replacement point inside the block. */
564 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
565 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
566 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
570 if (test > startcount) {
571 /* we don't need an extra rplpoint */
572 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
576 alloccount += bptr->indepth;
577 if (bptr->inlineinfo)
578 alloccount -= bptr->inlineinfo->throughcount;
580 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
584 } /* end basicblock loop */
586 /* if no points were found, there's nothing to do */
591 /* allocate replacement point array and allocation array */
593 rplpoints = MNEW(rplpoint, count);
594 regalloc = MNEW(rplalloc, alloccount);
597 /* initialize replacement point structs */
601 /* XXX try to share code with the counting loop! */
603 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
606 if (bptr->flags < BBFINISHED)
609 /* get info about this block */
612 iinfo = bptr->inlineinfo;
614 /* initialize javalocals at the start of this block */
616 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
618 /* create replacement points at targets of backward branches */
620 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
622 i = (iinfo) ? iinfo->throughcount : 0;
623 replace_create_replacement_point(jd, iinfo, rp++,
624 bptr->type, bptr->iinstr, &ra,
625 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
627 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
628 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
631 /* iterate over the instructions */
634 iend = iptr + bptr->icount;
636 for (; iptr != iend; ++iptr) {
638 #if defined(ENABLE_GC_CACAO)
640 md = iptr->sx.s23.s3.bte->md;
642 i = (iinfo) ? iinfo->throughcount : 0;
643 replace_create_replacement_point(jd, iinfo, rp++,
644 RPLPOINT_TYPE_CALL, iptr, &ra,
645 javalocals, iptr->sx.s23.s2.args,
646 iptr->s1.argcount - i,
651 case ICMD_INVOKESTATIC:
652 case ICMD_INVOKESPECIAL:
653 case ICMD_INVOKEVIRTUAL:
654 case ICMD_INVOKEINTERFACE:
655 INSTRUCTION_GET_METHODDESC(iptr, md);
657 i = (iinfo) ? iinfo->throughcount : 0;
658 replace_create_replacement_point(jd, iinfo, rp++,
659 RPLPOINT_TYPE_CALL, iptr, &ra,
660 javalocals, iptr->sx.s23.s2.args,
661 iptr->s1.argcount - i,
670 stack_javalocals_store(iptr, javalocals);
678 replace_create_replacement_point(jd, iinfo, rp++,
679 RPLPOINT_TYPE_RETURN, iptr, &ra,
680 NULL, &(iptr->s1.varindex), 1, 0);
684 replace_create_replacement_point(jd, iinfo, rp++,
685 RPLPOINT_TYPE_RETURN, iptr, &ra,
689 case ICMD_INLINE_START:
690 iinfo = replace_create_inline_start_replacement_point(
691 jd, rp++, iptr, &ra, javalocals);
693 /* javalocals may be set at next block start, or now */
694 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
697 case ICMD_INLINE_BODY:
698 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
700 jl = iinfo->javalocals_start;
702 /* get the javalocals from the following block start */
704 jl = bptr->next->javalocals;
706 /* create a non-trappable rplpoint */
707 replace_create_replacement_point(jd, iinfo, rp++,
708 RPLPOINT_TYPE_BODY, iptr, &ra,
710 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
713 case ICMD_INLINE_END:
714 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
715 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
716 iinfo = iptr->sx.s23.s3.inlineinfo;
718 if (iinfo->javalocals_end)
719 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
720 iinfo = iinfo->parent;
723 } /* end instruction loop */
724 } /* end basicblock loop */
726 assert((rp - rplpoints) == count);
727 assert((ra - regalloc) == alloccount);
729 /* store the data in the codeinfo */
731 code->rplpoints = rplpoints;
732 code->rplpointcount = count;
733 code->regalloc = regalloc;
734 code->regalloccount = alloccount;
735 code->globalcount = 0;
736 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
737 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
738 #if defined(HAS_ADDRESS_REGISTER_FILE)
739 code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
741 code->memuse = rd->memuse;
742 code->stackframesize = jd->cd->stackframesize;
744 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
745 REPLACE_COUNT_INC(stat_regallocs, alloccount);
747 /* everything alright */
753 /* replace_free_replacement_points *********************************************
755 Free memory used by replacement points.
758 code.............codeinfo whose replacement points should be freed.
760 *******************************************************************************/
762 void replace_free_replacement_points(codeinfo *code)
767 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
770 MFREE(code->regalloc,rplalloc,code->regalloccount);
772 code->rplpoints = NULL;
773 code->rplpointcount = 0;
774 code->regalloc = NULL;
775 code->regalloccount = 0;
776 code->globalcount = 0;
780 /******************************************************************************/
781 /* PART II: Activating / deactivating replacement points */
782 /******************************************************************************/
785 /* replace_activate_replacement_points *****************************************
787 Activate the replacement points of the given compilation unit. When this
788 function returns, the replacement points are "armed", so each thread
789 reaching one of the points will enter the replacement mechanism.
792 code.............codeinfo of which replacement points should be
794 mappable.........if true, only mappable replacement points are
797 *******************************************************************************/
799 void replace_activate_replacement_points(codeinfo *code, bool mappable)
806 assert(code->savedmcode == NULL);
808 /* count trappable replacement points */
811 i = code->rplpointcount;
812 rp = code->rplpoints;
814 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
817 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
823 /* allocate buffer for saved machine code */
825 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
826 code->savedmcode = savedmcode;
827 savedmcode += count * REPLACEMENT_PATCH_SIZE;
829 /* activate trappable replacement points */
830 /* (in reverse order to handle overlapping points within basic blocks) */
832 i = code->rplpointcount;
833 rp = code->rplpoints + i;
835 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
837 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
840 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
843 DOLOG( printf("activate replacement point:\n");
844 replace_replacement_point_println(rp, 1); fflush(stdout); );
846 savedmcode -= REPLACEMENT_PATCH_SIZE;
848 #if defined(ENABLE_JIT)
849 # if defined(ENABLE_DISASSEMBLER)
850 DOLOG( printf("\tinstruction before: ");
851 disassinstr(rp->pc); fflush(stdout); );
854 md_patch_replacement_point(rp->pc, savedmcode, false);
856 # if defined(ENABLE_DISASSEMBLER)
857 DOLOG( printf("\tinstruction after : ");
858 disassinstr(rp->pc); fflush(stdout); );
862 rp->flags |= RPLPOINT_FLAG_ACTIVE;
865 assert(savedmcode == code->savedmcode);
869 /* replace_deactivate_replacement_points ***************************************
871 Deactivate a replacement points in the given compilation unit.
872 When this function returns, the replacement points will be "un-armed",
873 that is a each thread reaching a point will just continue normally.
876 code.............the compilation unit
878 *******************************************************************************/
880 void replace_deactivate_replacement_points(codeinfo *code)
887 if (code->savedmcode == NULL) {
888 /* disarm countdown points by patching the branches */
890 i = code->rplpointcount;
891 rp = code->rplpoints;
893 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
894 == RPLPOINT_FLAG_COUNTDOWN)
897 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
904 assert(code->savedmcode != NULL);
905 savedmcode = code->savedmcode;
907 /* de-activate each trappable replacement point */
909 i = code->rplpointcount;
910 rp = code->rplpoints;
913 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
918 DOLOG( printf("deactivate replacement point:\n");
919 replace_replacement_point_println(rp, 1); fflush(stdout); );
921 #if defined(ENABLE_JIT)
922 # if defined(ENABLE_DISASSEMBLER)
923 DOLOG( printf("\tinstruction before: ");
924 disassinstr(rp->pc); fflush(stdout); );
927 md_patch_replacement_point(rp->pc, savedmcode, true);
929 # if defined(ENABLE_DISASSEMBLER)
930 DOLOG( printf("\tinstruction before: ");
931 disassinstr(rp->pc); fflush(stdout); );
935 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
937 savedmcode += REPLACEMENT_PATCH_SIZE;
940 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
942 /* free saved machine code */
944 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
945 code->savedmcode = NULL;
949 /******************************************************************************/
950 /* PART III: The replacement mechanism */
951 /******************************************************************************/
954 /* replace_read_value **********************************************************
956 Read a value with the given allocation from the execution state.
959 es...............execution state
960 ra...............allocation
961 javaval..........where to put the value
964 *javaval.........the value
966 *******************************************************************************/
968 static void replace_read_value(executionstate_t *es,
970 replace_val_t *javaval)
972 if (ra->flags & INMEMORY) {
973 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
974 #ifdef HAS_4BYTE_STACKSLOT
975 if (IS_2_WORD_TYPE(ra->type)) {
976 javaval->l = *(u8*)(es->sp + ra->regoff);
980 javaval->p = *(ptrint*)(es->sp + ra->regoff);
981 #ifdef HAS_4BYTE_STACKSLOT
986 /* allocated register */
987 if (IS_FLT_DBL_TYPE(ra->type)) {
988 javaval->d = es->fltregs[ra->regoff];
990 if (ra->type == TYPE_FLT)
991 javaval->f = javaval->d;
993 #if defined(HAS_ADDRESS_REGISTER_FILE)
994 else if (IS_ADR_TYPE(ra->type)) {
995 javaval->p = es->adrregs[ra->regoff];
999 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1000 if (ra->type == TYPE_LNG) {
1001 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
1002 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
1005 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
1006 javaval->p = es->intregs[ra->regoff];
1012 /* replace_write_value *********************************************************
1014 Write a value to the given allocation in the execution state.
1017 es...............execution state
1018 ra...............allocation
1019 *javaval.........the value
1021 *******************************************************************************/
1023 static void replace_write_value(executionstate_t *es,
1025 replace_val_t *javaval)
1027 if (ra->flags & INMEMORY) {
1028 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1029 #ifdef HAS_4BYTE_STACKSLOT
1030 if (IS_2_WORD_TYPE(ra->type)) {
1031 *(u8*)(es->sp + ra->regoff) = javaval->l;
1035 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1036 #ifdef HAS_4BYTE_STACKSLOT
1041 /* allocated register */
1044 es->fltregs[ra->regoff] = (double) javaval->f;
1047 es->fltregs[ra->regoff] = javaval->d;
1049 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1051 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1052 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1055 #if defined(HAS_ADDRESS_REGISTER_FILE)
1057 es->adrregs[ra->regoff] = javaval->p;
1060 es->intregs[ra->regoff] = javaval->p;
1066 /* replace_new_sourceframe *****************************************************
1068 Allocate a new source frame and insert it at the front of the frame list.
1071 ss...............the source state
1074 ss->frames.......set to new frame (the new head of the frame list).
1077 returns the new frame
1079 *******************************************************************************/
1081 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1083 sourceframe_t *frame;
1085 frame = DNEW(sourceframe_t);
1086 MZERO(frame, sourceframe_t, 1);
1088 frame->down = ss->frames;
1095 /* replace_read_executionstate *************************************************
1097 Read a source frame from the given executions state.
1098 The new source frame is pushed to the front of the frame list of the
1102 rp...............replacement point at which `es` was taken
1103 es...............execution state
1104 ss...............the source state to add the source frame to
1105 topframe.........true, if the first (top-most) source frame on the
1109 *ss..............the source state with the newly created source frame
1112 *******************************************************************************/
1114 static s4 replace_normalize_type_map[] = {
1115 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1116 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1117 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1118 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1119 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1120 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1121 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1125 static void replace_read_executionstate(rplpoint *rp,
1126 executionstate_t *es,
1135 sourceframe_t *frame;
1138 stackslot_t *basesp;
1140 code = code_find_codeinfo_for_pc(rp->pc);
1142 topslot = TOP_IS_NORMAL;
1146 sp = (stackslot_t *) es->sp;
1148 /* in some cases the top stack slot is passed in REG_ITMP1 */
1150 if (rp->type == BBTYPE_EXH) {
1151 topslot = TOP_IS_IN_ITMP1;
1154 /* calculate base stack pointer */
1156 basesp = sp + code->stackframesize;
1158 /* create the source frame */
1160 frame = replace_new_sourceframe(ss);
1161 frame->method = rp->method;
1163 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1164 frame->type = replace_normalize_type_map[rp->type];
1166 frame->fromcode = code;
1168 /* read local variables */
1170 count = m->maxlocals;
1171 frame->javalocalcount = count;
1172 frame->javalocals = DMNEW(replace_val_t, count);
1173 frame->javalocaltype = DMNEW(u1, count);
1175 /* mark values as undefined */
1176 for (i=0; i<count; ++i) {
1177 #if !defined(NDEBUG)
1178 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1180 frame->javalocaltype[i] = TYPE_VOID;
1183 /* some entries in the intregs array are not meaningful */
1184 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1185 #if !defined(NDEBUG)
1186 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1188 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1190 #endif /* !defined(NDEBUG) */
1192 /* read javalocals */
1194 count = rp->regalloccount;
1197 while (count && (i = ra->index) >= 0) {
1198 assert(i < m->maxlocals);
1199 frame->javalocaltype[i] = ra->type;
1200 if (ra->type == TYPE_RET)
1201 frame->javalocals[i].i = ra->regoff;
1203 replace_read_value(es, ra, frame->javalocals + i);
1208 /* read instance, if this is the first rplpoint */
1210 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1211 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1213 /* we are at the start of the method body, so if local 0 is set, */
1214 /* it is the instance. */
1215 if (frame->javalocaltype[0] == TYPE_ADR)
1216 frame->instance = frame->javalocals[0];
1221 md = rp->method->parseddesc;
1223 assert(md->paramcount >= 1);
1224 instra.type = TYPE_ADR;
1225 instra.regoff = md->params[0].regoff;
1226 if (md->params[0].inmemory) {
1227 instra.flags = INMEMORY;
1228 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1233 replace_read_value(es, &instra, &(frame->instance));
1236 #if defined(__I386__)
1237 else if (!(rp->method->flags & ACC_STATIC)) {
1238 /* On i386 we always pass the first argument on stack. */
1239 frame->instance.a = *(java_object_t **)(basesp + 1);
1242 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1244 /* read stack slots */
1246 frame->javastackdepth = count;
1247 frame->javastack = DMNEW(replace_val_t, count);
1248 frame->javastacktype = DMNEW(u1, count);
1250 #if !defined(NDEBUG)
1251 /* mark values as undefined */
1252 for (i=0; i<count; ++i) {
1253 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1254 frame->javastacktype[i] = TYPE_VOID;
1256 #endif /* !defined(NDEBUG) */
1260 /* the first stack slot is special in SBR and EXH blocks */
1262 if (topslot == TOP_IS_ON_STACK) {
1265 assert(ra->index == RPLALLOC_STACK);
1266 assert(ra->type == TYPE_ADR);
1267 frame->javastack[i].p = sp[-1];
1268 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1273 else if (topslot == TOP_IS_IN_ITMP1) {
1276 assert(ra->index == RPLALLOC_STACK);
1277 assert(ra->type == TYPE_ADR);
1278 frame->javastack[i].p = es->intregs[REG_ITMP1];
1279 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1284 else if (topslot == TOP_IS_VOID) {
1287 assert(ra->index == RPLALLOC_STACK);
1288 frame->javastack[i].l = 0;
1289 frame->javastacktype[i] = TYPE_VOID;
1295 /* read remaining stack slots */
1297 for (; count--; ra++) {
1298 if (ra->index == RPLALLOC_SYNC) {
1299 assert(rp->type == RPLPOINT_TYPE_INLINE);
1301 /* only read synchronization slots when traversing an inline point */
1304 sourceframe_t *calleeframe = frame->down;
1305 assert(calleeframe);
1306 assert(calleeframe->syncslotcount == 0);
1307 assert(calleeframe->syncslots == NULL);
1309 calleeframe->syncslotcount = 1;
1310 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1311 replace_read_value(es,ra,calleeframe->syncslots);
1314 frame->javastackdepth--;
1318 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1320 /* do not read parameters of calls down the call chain */
1322 if (!topframe && ra->index == RPLALLOC_PARAM) {
1323 frame->javastackdepth--;
1326 if (ra->type == TYPE_RET)
1327 frame->javastack[i].i = ra->regoff;
1329 replace_read_value(es,ra,frame->javastack + i);
1330 frame->javastacktype[i] = ra->type;
1337 /* replace_write_executionstate ************************************************
1339 Pop a source frame from the front of the frame list of the given source state
1340 and write its values into the execution state.
1343 rp...............replacement point for which execution state should be
1345 es...............the execution state to modify
1346 ss...............the given source state
1347 topframe.........true, if this is the last (top-most) source frame to be
1351 *es..............the execution state derived from the source state
1353 *******************************************************************************/
1355 static void replace_write_executionstate(rplpoint *rp,
1356 executionstate_t *es,
1365 sourceframe_t *frame;
1368 stackslot_t *basesp;
1370 code = code_find_codeinfo_for_pc(rp->pc);
1372 topslot = TOP_IS_NORMAL;
1374 /* pop a source frame */
1378 ss->frames = frame->down;
1380 /* calculate stack pointer */
1382 sp = (stackslot_t *) es->sp;
1384 basesp = sp + code->stackframesize;
1386 /* in some cases the top stack slot is passed in REG_ITMP1 */
1388 if (rp->type == BBTYPE_EXH) {
1389 topslot = TOP_IS_IN_ITMP1;
1392 /* write javalocals */
1395 count = rp->regalloccount;
1397 while (count && (i = ra->index) >= 0) {
1398 assert(i < m->maxlocals);
1399 assert(i < frame->javalocalcount);
1400 assert(ra->type == frame->javalocaltype[i]);
1401 if (ra->type == TYPE_RET) {
1402 /* XXX assert that it matches this rplpoint */
1405 replace_write_value(es, ra, frame->javalocals + i);
1410 /* write stack slots */
1414 /* the first stack slot is special in SBR and EXH blocks */
1416 if (topslot == TOP_IS_ON_STACK) {
1419 assert(ra->index == RPLALLOC_STACK);
1420 assert(i < frame->javastackdepth);
1421 assert(frame->javastacktype[i] == TYPE_ADR);
1422 sp[-1] = frame->javastack[i].p;
1427 else if (topslot == TOP_IS_IN_ITMP1) {
1430 assert(ra->index == RPLALLOC_STACK);
1431 assert(i < frame->javastackdepth);
1432 assert(frame->javastacktype[i] == TYPE_ADR);
1433 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1438 else if (topslot == TOP_IS_VOID) {
1441 assert(ra->index == RPLALLOC_STACK);
1442 assert(i < frame->javastackdepth);
1443 assert(frame->javastacktype[i] == TYPE_VOID);
1449 /* write remaining stack slots */
1451 for (; count--; ra++) {
1452 if (ra->index == RPLALLOC_SYNC) {
1453 assert(rp->type == RPLPOINT_TYPE_INLINE);
1455 /* only write synchronization slots when traversing an inline point */
1458 assert(frame->down);
1459 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1460 assert(frame->down->syncslots != NULL);
1462 replace_write_value(es,ra,frame->down->syncslots);
1467 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1469 /* do not write parameters of calls down the call chain */
1471 if (!topframe && ra->index == RPLALLOC_PARAM) {
1474 ra->index = RPLALLOC_PARAM;
1477 replace_write_value(es,ra,&v);
1481 assert(i < frame->javastackdepth);
1482 assert(ra->type == frame->javastacktype[i]);
1483 if (ra->type == TYPE_RET) {
1484 /* XXX assert that it matches this rplpoint */
1487 replace_write_value(es,ra,frame->javastack + i);
1499 /* md_pop_stackframe ***********************************************************
1501 Restore callee-saved registers (including the RA register),
1502 set the stack pointer to the next stackframe,
1503 set the PC to the return address of the popped frame.
1505 *** This function imitates the effects of the method epilog ***
1506 *** and returning from the method call. ***
1509 es...............execution state
1512 *es..............the execution state after popping the stack frame
1513 NOTE: es->code and es->pv are NOT updated.
1515 *******************************************************************************/
1517 void md_pop_stackframe(executionstate_t *es)
1523 stackslot_t *basesp;
1528 /* alignment offset of RA */
1531 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1532 if (es->code->stackframesize)
1533 ra_align_off = SIZE_OF_STACKSLOT - SIZEOF_VOID_P;
1536 /* read the return address */
1538 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1539 if (code_is_leafmethod(es->code))
1543 ra = (u1*) md_stacktrace_get_returnaddress(es->sp,
1544 SIZE_OF_STACKSLOT * es->code->stackframesize + ra_align_off);
1546 /* calculate the base of the stack frame */
1548 sp = (stackslot_t *) es->sp;
1549 basesp = sp + es->code->stackframesize;
1551 /* restore return address, if part of frame */
1553 #if defined(REPLACE_RA_TOP_OF_FRAME)
1554 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1555 if (!code_is_leafmethod(es->code))
1557 es->ra = (u1*) (ptrint) *--basesp;
1558 #endif /* REPLACE_RA_TOP_OF_FRAME */
1560 #if defined(REPLACE_RA_LINKAGE_AREA)
1561 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1562 if (!code_is_leafmethod(es->code))
1564 es->ra = (u1*) (ptrint) basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1565 #endif /* REPLACE_RA_LINKAGE_AREA */
1567 /* restore saved int registers */
1570 for (i=0; i<es->code->savedintcount; ++i) {
1571 while (nregdescint[--reg] != REG_SAV)
1573 es->intregs[reg] = *--basesp;
1576 /* restore saved flt registers */
1580 for (i=0; i<es->code->savedfltcount; ++i) {
1581 while (nregdescfloat[--reg] != REG_SAV)
1583 basesp -= STACK_SLOTS_PER_FLOAT;
1584 es->fltregs[reg] = *(double*)basesp;
1587 #if defined(HAS_ADDRESS_REGISTER_FILE)
1588 /* restore saved adr registers */
1591 for (i=0; i<es->code->savedadrcount; ++i) {
1592 while (nregdescadr[--reg] != REG_SAV)
1594 es->adrregs[reg] = *--basesp;
1598 /* adjust the stackpointer */
1600 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1602 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1603 es->sp += ra_align_off + SIZEOF_VOID_P; /* skip return address */
1606 /* set the program counter to the return address */
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)
1616 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1617 for (i=0; i<FLT_REG_CNT; ++i)
1618 if (nregdescfloat[i] != REG_SAV)
1619 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1620 # if defined(HAS_ADDRESS_REGISTER_FILE)
1621 for (i=0; i<ADR_REG_CNT; ++i)
1622 if (nregdescadr[i] != REG_SAV)
1623 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1625 #endif /* !defined(NDEBUG) */
1629 /* md_push_stackframe **********************************************************
1631 Save the given return address, build the new stackframe,
1632 and store callee-saved registers.
1634 *** This function imitates the effects of a call and the ***
1635 *** method prolog of the callee. ***
1638 es...............execution state
1639 calleecode.......the code we are "calling"
1640 ra...............the return address to save
1643 *es..............the execution state after pushing the stack frame
1644 NOTE: es->pc, es->code, and es->pv are NOT updated.
1646 *******************************************************************************/
1648 void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra)
1652 stackslot_t *basesp;
1658 /* write the return address */
1660 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1661 es->sp -= SIZEOF_VOID_P;
1662 *((void **)es->sp) = (void *) ra;
1663 if (calleecode->stackframesize)
1664 es->sp -= (SIZE_OF_STACKSLOT - SIZEOF_VOID_P);
1665 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1667 es->ra = (u1*) (ptrint) ra;
1669 /* build the stackframe */
1671 DOLOG( printf("building stackframe of %d words at %p\n",
1672 calleecode->stackframesize, (void*)es->sp); );
1674 sp = (stackslot_t *) es->sp;
1677 sp -= calleecode->stackframesize;
1680 /* in debug mode, invalidate stack frame first */
1682 /* XXX may not invalidate linkage area used by native code! */
1684 #if !defined(NDEBUG) && 0
1685 for (i=0; i< (basesp - sp) && i < 1; ++i) {
1686 sp[i] = 0xdeaddeadU;
1690 #if defined(__I386__)
1691 /* Stackslot 0 may contain the object instance for vftbl patching.
1692 Destroy it, so there's no undefined value used. */
1693 if ((basesp - sp) > 0) {
1698 /* save the return address register */
1700 #if defined(REPLACE_RA_TOP_OF_FRAME)
1701 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1702 if (!code_is_leafmethod(calleecode))
1704 *--basesp = (ptrint) ra;
1705 #endif /* REPLACE_RA_TOP_OF_FRAME */
1707 #if defined(REPLACE_RA_LINKAGE_AREA)
1708 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1709 if (!code_is_leafmethod(calleecode))
1711 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1712 #endif /* REPLACE_RA_LINKAGE_AREA */
1714 /* save int registers */
1717 for (i=0; i<calleecode->savedintcount; ++i) {
1718 while (nregdescint[--reg] != REG_SAV)
1720 *--basesp = es->intregs[reg];
1722 /* XXX may not clobber saved regs used by native code! */
1723 #if !defined(NDEBUG) && 0
1724 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1728 /* save flt registers */
1732 for (i=0; i<calleecode->savedfltcount; ++i) {
1733 while (nregdescfloat[--reg] != REG_SAV)
1735 basesp -= STACK_SLOTS_PER_FLOAT;
1736 *(double*)basesp = es->fltregs[reg];
1738 /* XXX may not clobber saved regs used by native code! */
1739 #if !defined(NDEBUG) && 0
1740 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1744 #if defined(HAS_ADDRESS_REGISTER_FILE)
1745 /* save adr registers */
1748 for (i=0; i<calleecode->savedadrcount; ++i) {
1749 while (nregdescadr[--reg] != REG_SAV)
1751 *--basesp = es->adrregs[reg];
1753 /* XXX may not clobber saved regs used by native code! */
1754 #if !defined(NDEBUG) && 0
1755 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1762 /* replace_pop_activation_record ***********************************************
1764 Peel a stack frame from the execution state.
1766 *** This function imitates the effects of the method epilog ***
1767 *** and returning from the method call. ***
1770 es...............execution state
1771 frame............source frame, receives synchronization slots
1774 *es..............the execution state after popping the stack frame
1777 the return address of the poped activation record
1779 *******************************************************************************/
1781 u1* replace_pop_activation_record(executionstate_t *es,
1782 sourceframe_t *frame)
1793 /* calculate the base of the stack frame */
1795 sp = (stackslot_t *) es->sp;
1796 assert(frame->syncslotcount == 0);
1797 assert(frame->syncslots == NULL);
1798 count = code_get_sync_slot_count(es->code);
1799 frame->syncslotcount = count;
1800 frame->syncslots = DMNEW(replace_val_t, count);
1801 for (i=0; i<count; ++i) {
1802 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX md_ function */
1805 /* pop the stackframe */
1807 md_pop_stackframe(es);
1811 DOLOG( printf("RA = %p\n", (void*)ra); );
1813 /* Subtract one from the PC so we do not hit the replacement point */
1814 /* of the instruction following the call, if there is one. */
1818 /* find the new codeinfo */
1820 void* pv = md_codegen_get_pv_from_pc(ra);
1821 DOLOG( printf("PV = %p\n", pv); );
1823 code = code_get_codeinfo_for_pv(pv);
1824 DOLOG( printf("CODE = %p\n", (void*) code); );
1826 /* return NULL if we reached native code */
1828 es->pv = (uint8_t*) pv;
1831 return (code) ? ra : NULL;
1835 /* replace_patch_method_pointer ************************************************
1837 Patch a method pointer (may be in code, data segment, vftbl, or interface
1841 mpp..............address of the method pointer to patch
1842 entrypoint.......the new entrypoint of the method
1843 kind.............kind of call to patch, used only for debugging
1845 *******************************************************************************/
1847 static void replace_patch_method_pointer(methodptr *mpp,
1848 methodptr entrypoint,
1851 #if !defined(NDEBUG)
1856 DOLOG( printf("patch method pointer from: %p to %p\n",
1857 (void*) *mpp, (void*)entrypoint); );
1859 #if !defined(NDEBUG)
1860 oldcode = code_get_codeinfo_for_pv(*mpp);
1861 newcode = code_get_codeinfo_for_pv(entrypoint);
1863 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1864 method_println(oldcode->m);
1865 printf("\t with %p ", (void*) newcode);
1866 method_println(newcode->m); );
1868 assert(oldcode->m == newcode->m);
1871 /* write the new entrypoint */
1873 *mpp = (methodptr) entrypoint;
1877 /* replace_patch_class *********************************************************
1879 Patch a method in the given class.
1882 vftbl............vftbl of the class
1883 m................the method to patch
1884 oldentrypoint....the old entrypoint to replace
1885 entrypoint.......the new entrypoint
1887 *******************************************************************************/
1889 void replace_patch_class(vftbl_t *vftbl,
1898 /* patch the vftbl of the class */
1900 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1904 /* patch the interface tables */
1906 assert(oldentrypoint);
1908 for (i=0; i < vftbl->interfacetablelength; ++i) {
1909 mpp = vftbl->interfacetable[-i];
1910 mppend = mpp + vftbl->interfacevftbllength[i];
1911 for (; mpp != mppend; ++mpp)
1912 if (*mpp == oldentrypoint) {
1913 replace_patch_method_pointer(mpp, entrypoint, "interface");
1919 /* replace_patch_class_hierarchy ***********************************************
1921 Patch a method in all loaded classes.
1924 m................the method to patch
1925 oldentrypoint....the old entrypoint to replace
1926 entrypoint.......the new entrypoint
1928 *******************************************************************************/
1930 struct replace_patch_data_t {
1936 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1938 vftbl_t *vftbl = c->vftbl;
1941 && vftbl->vftbllength > pd->m->vftblindex
1942 && (void*) vftbl->table[pd->m->vftblindex] != (void*) (uintptr_t) &asm_abstractmethoderror
1943 && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
1945 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1949 void replace_patch_class_hierarchy(methodinfo *m,
1953 struct replace_patch_data_t pd;
1956 pd.oldentrypoint = oldentrypoint;
1957 pd.entrypoint = entrypoint;
1959 DOLOG_SHORT( printf("patching class hierarchy: ");
1960 method_println(m); );
1962 classcache_foreach_loaded_class(
1963 (classcache_foreach_functionptr_t) &replace_patch_callback,
1968 /* replace_patch_future_calls **************************************************
1970 Analyse a call site and depending on the kind of call patch the call, the
1971 virtual function table, or the interface table.
1974 ra...............return address pointing after the call site
1975 callerframe......source frame of the caller
1976 calleeframe......source frame of the callee, must have been mapped
1978 *******************************************************************************/
1980 void replace_patch_future_calls(u1 *ra,
1981 sourceframe_t *callerframe,
1982 sourceframe_t *calleeframe)
1985 methodptr entrypoint;
1986 methodptr oldentrypoint;
1989 codeinfo *calleecode;
1990 methodinfo *calleem;
1995 assert(callerframe->down == calleeframe);
1997 /* get the new codeinfo and the method that shall be entered */
1999 calleecode = calleeframe->tocode;
2002 calleem = calleeframe->method;
2003 assert(calleem == calleecode->m);
2005 entrypoint = (methodptr) calleecode->entrypoint;
2007 /* check if we are at an method entry rplpoint at the innermost frame */
2009 atentry = (calleeframe->down == NULL)
2010 && !(calleem->flags & ACC_STATIC)
2011 && (calleeframe->fromrp->id == 0); /* XXX */
2013 /* get the position to patch, in case it was a statically bound call */
2015 pv = callerframe->fromcode->entrypoint;
2016 patchpos = (u1*) md_jit_method_patch_address(pv, ra, NULL);
2018 if (patchpos == NULL) {
2019 /* the call was dispatched dynamically */
2021 /* we can only patch such calls if we are at the entry point */
2023 #if !defined(__I386__)
2024 /* On i386 we always know the instance argument. */
2029 assert((calleem->flags & ACC_STATIC) == 0);
2031 oldentrypoint = calleeframe->fromcode->entrypoint;
2033 /* we need to know the instance */
2035 if (!calleeframe->instance.a) {
2036 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
2037 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
2043 obj = calleeframe->instance.a;
2046 assert(vftbl->clazz->vftbl == vftbl);
2048 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->clazz); );
2050 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
2053 /* the call was statically bound */
2055 #if defined(__I386__)
2056 /* It happens that there is a patcher trap. (pm) */
2057 if (*(u2 *)(patchpos - 1) == 0x0b0f) {
2060 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
2065 /* replace_push_activation_record **********************************************
2067 Push a stack frame onto the execution state.
2069 *** This function imitates the effects of a call and the ***
2070 *** method prolog of the callee. ***
2073 es...............execution state
2074 rpcall...........the replacement point at the call site
2075 callerframe......source frame of the caller, or NULL for creating the
2077 calleeframe......source frame of the callee, must have been mapped
2080 *es..............the execution state after pushing the stack frame
2082 *******************************************************************************/
2084 void replace_push_activation_record(executionstate_t *es,
2086 sourceframe_t *callerframe,
2087 sourceframe_t *calleeframe)
2093 codeinfo *calleecode;
2096 assert(!rpcall || callerframe);
2097 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
2098 assert(!rpcall || rpcall == callerframe->torp);
2099 assert(calleeframe);
2100 assert(!callerframe || calleeframe == callerframe->down);
2102 /* the compilation unit we are entering */
2104 calleecode = calleeframe->tocode;
2107 /* calculate the return address */
2110 ra = rpcall->pc + rpcall->callsize;
2112 ra = es->pc + 1 /* XXX this is ugly */;
2114 /* push the stackframe */
2116 md_push_stackframe(es, calleecode, ra);
2118 /* we move into a new code unit, set code, PC, PV */
2120 es->code = calleecode;
2121 es->pc = calleecode->entrypoint; /* XXX not needed? */
2122 es->pv = calleecode->entrypoint;
2124 /* write slots used for synchronization */
2126 sp = (stackslot_t *) es->sp;
2127 count = code_get_sync_slot_count(calleecode);
2128 assert(count == calleeframe->syncslotcount);
2129 for (i=0; i<count; ++i) {
2130 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2133 /* redirect future invocations */
2135 if (callerframe && rpcall) {
2136 #if defined(REPLACE_PATCH_ALL)
2137 if (rpcall->type == callerframe->fromrp->type)
2139 if (rpcall == callerframe->fromrp)
2141 replace_patch_future_calls(ra, callerframe, calleeframe);
2146 /* replace_find_replacement_point **********************************************
2148 Find the replacement point in the given code corresponding to the
2149 position given in the source frame.
2152 code.............the codeinfo in which to search the rplpoint
2153 frame............the source frame defining the position to look for
2154 parent...........parent replacement point to match
2157 the replacement point
2159 *******************************************************************************/
2161 rplpoint * replace_find_replacement_point(codeinfo *code,
2162 sourceframe_t *frame,
2175 DOLOG( printf("searching replacement point for:\n");
2176 replace_source_frame_println(frame); );
2180 DOLOG( printf("code = %p\n", (void*)code); );
2182 rp = code->rplpoints;
2183 i = code->rplpointcount;
2185 if (rp->id == frame->id && rp->method == frame->method
2186 && rp->parent == parent
2187 && replace_normalize_type_map[rp->type] == frame->type)
2189 /* check if returnAddresses match */
2190 /* XXX optimize: only do this if JSRs in method */
2191 DOLOG( printf("checking match for:");
2192 replace_replacement_point_println(rp, 1); fflush(stdout); );
2195 for (j = rp->regalloccount; j--; ++ra) {
2196 if (ra->type == TYPE_RET) {
2197 if (ra->index == RPLALLOC_STACK) {
2198 assert(stacki < frame->javastackdepth);
2199 if (frame->javastack[stacki].i != ra->regoff)
2204 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2205 if (frame->javalocals[ra->index].i != ra->regoff)
2218 #if !defined(NDEBUG)
2219 printf("candidate replacement points were:\n");
2220 rp = code->rplpoints;
2221 i = code->rplpointcount;
2223 replace_replacement_point_println(rp, 1);
2227 vm_abort("no matching replacement point found");
2228 return NULL; /* NOT REACHED */
2232 /* replace_find_replacement_point_for_pc ***************************************
2234 Find the nearest replacement point at or before the given PC. The
2235 given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
2236 the replacement point to be found.
2239 code.............compilation unit the PC is in
2240 pc...............the machine code PC
2243 the replacement point found, or
2244 NULL if no replacement point was found
2246 *******************************************************************************/
2248 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc, unsigned desired_flags)
2254 DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
2255 method_println(code->m); );
2259 rp = code->rplpoints;
2260 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2261 DOLOG( replace_replacement_point_println(rp, 2); );
2262 if (rp->pc <= pc && rp->pc + rp->callsize >= pc) {
2263 if (desired_flags) {
2264 if (rp->flags & desired_flags) {
2276 /* replace_pop_native_frame ****************************************************
2278 Unroll a native frame in the execution state and create a source frame
2282 es...............current execution state
2283 ss...............the current source state
2284 sfi..............stackframeinfo for the native frame
2287 es...............execution state after unrolling the native frame
2288 ss...............gets the added native source frame
2290 *******************************************************************************/
2292 static void replace_pop_native_frame(executionstate_t *es,
2294 stackframeinfo_t *sfi)
2296 sourceframe_t *frame;
2302 frame = replace_new_sourceframe(ss);
2306 /* remember pc and size of native frame */
2308 frame->nativepc = es->pc;
2309 frame->nativeframesize = (es->sp != 0) ? (((uintptr_t) sfi->sp) - ((uintptr_t) es->sp)) : 0;
2310 assert(frame->nativeframesize >= 0);
2312 /* remember values of saved registers */
2315 for (i=0; i<INT_REG_CNT; ++i) {
2316 if (nregdescint[i] == REG_SAV)
2317 frame->nativesavint[j++] = es->intregs[i];
2321 for (i=0; i<FLT_REG_CNT; ++i) {
2322 if (nregdescfloat[i] == REG_SAV)
2323 frame->nativesavflt[j++] = es->fltregs[i];
2326 #if defined(HAS_ADDRESS_REGISTER_FILE)
2328 for (i=0; i<ADR_REG_CNT; ++i) {
2329 if (nregdescadr[i] == REG_SAV)
2330 frame->nativesavadr[j++] = es->adrregs[i];
2334 /* restore saved registers */
2336 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2338 for (i=0; i<INT_REG_CNT; ++i) {
2339 if (nregdescint[i] == REG_SAV)
2340 es->intregs[i] = sfi->intregs[j++];
2343 /* XXX we don't have them, yet, in the sfi, so clear them */
2345 for (i=0; i<INT_REG_CNT; ++i) {
2346 if (nregdescint[i] == REG_SAV)
2351 /* XXX we don't have float registers in the sfi, so clear them */
2353 for (i=0; i<FLT_REG_CNT; ++i) {
2354 if (nregdescfloat[i] == REG_SAV)
2355 es->fltregs[i] = 0.0;
2358 #if defined(HAS_ADDRESS_REGISTER_FILE)
2359 # if defined(ENABLE_GC_CACAO)
2361 for (i=0; i<ADR_REG_CNT; ++i) {
2362 if (nregdescadr[i] == REG_SAV)
2363 es->adrregs[i] = sfi->adrregs[j++];
2366 for (i=0; i<ADR_REG_CNT; ++i) {
2367 if (nregdescadr[i] == REG_SAV)
2373 /* restore codeinfo of the native stub */
2375 code = code_get_codeinfo_for_pv(sfi->pv);
2377 /* restore sp, pv, pc and codeinfo of the parent method */
2379 /* XXX michi: use this instead:
2380 es->sp = sfi->sp + code->stackframesize; */
2381 es->sp = (uint8_t*) (((uintptr_t) sfi->sp) + (*(s4 *) (((uintptr_t) sfi->pv) + FrameSize)));
2382 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2383 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
2385 es->pv = (uint8_t*) md_codegen_get_pv_from_pc(sfi->ra);
2386 es->pc = (uint8_t*) (((uintptr_t) ((sfi->xpc) ? sfi->xpc : sfi->ra)) - 1);
2387 es->code = code_get_codeinfo_for_pv(es->pv);
2391 /* replace_push_native_frame ***************************************************
2393 Rebuild a native frame onto the execution state and remove its source frame.
2395 Note: The native frame is "rebuild" by setting fields like PC and stack
2396 pointer in the execution state accordingly. Values in the
2397 stackframeinfo may be modified, but the actual stack frame of the
2398 native code is not touched.
2401 es...............current execution state
2402 ss...............the current source state
2405 es...............execution state after re-rolling the native frame
2406 ss...............the native source frame is removed
2408 *******************************************************************************/
2410 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2412 sourceframe_t *frame;
2418 DOLOG( printf("pushing native frame\n"); );
2420 /* remove the frame from the source state */
2424 assert(REPLACE_IS_NATIVE_FRAME(frame));
2426 ss->frames = frame->down;
2428 /* skip sp for the native stub */
2430 es->sp -= (*(s4 *) (((uintptr_t) frame->sfi->pv) + FrameSize));
2431 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2432 es->sp -= SIZE_OF_STACKSLOT; /* skip return address */
2435 /* assert that the native frame has not moved */
2437 assert(es->sp == frame->sfi->sp);
2439 /* update saved registers in the stackframeinfo */
2441 #if defined(ENABLE_GC_CACAO)
2443 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2444 for (i=0; i<INT_REG_CNT; ++i) {
2445 if (nregdescint[i] == REG_SAV)
2446 frame->sfi->intregs[j++] = es->intregs[i];
2449 for (i=0; i<ADR_REG_CNT; ++i) {
2450 if (nregdescadr[i] == REG_SAV)
2451 frame->sfi->adrregs[j++] = es->adrregs[i];
2455 /* XXX leave float registers untouched here */
2458 /* restore saved registers */
2461 for (i=0; i<INT_REG_CNT; ++i) {
2462 if (nregdescint[i] == REG_SAV)
2463 es->intregs[i] = frame->nativesavint[j++];
2467 for (i=0; i<FLT_REG_CNT; ++i) {
2468 if (nregdescfloat[i] == REG_SAV)
2469 es->fltregs[i] = frame->nativesavflt[j++];
2472 #if defined(HAS_ADDRESS_REGISTER_FILE)
2474 for (i=0; i<ADR_REG_CNT; ++i) {
2475 if (nregdescadr[i] == REG_SAV)
2476 es->adrregs[i] = frame->nativesavadr[j++];
2480 /* skip the native frame on the machine stack */
2482 es->sp -= frame->nativeframesize;
2484 /* set the pc the next frame must return to */
2486 es->pc = frame->nativepc;
2490 /* replace_recover_source_state ************************************************
2492 Recover the source state from the given replacement point and execution
2496 rp...............replacement point that has been reached, if any
2497 sfi..............stackframeinfo, if called from native code
2498 es...............execution state at the replacement point rp
2503 *******************************************************************************/
2505 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2506 stackframeinfo_t *sfi,
2507 executionstate_t *es)
2512 #if defined(REPLACE_STATISTICS)
2516 /* create the source frame structure in dump memory */
2518 ss = DNEW(sourcestate_t);
2521 /* each iteration of the loop recovers one source frame */
2528 DOLOG( executionstate_println(es); );
2530 /* if we are not at a replacement point, it is a native frame */
2533 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2536 replace_pop_native_frame(es, ss, sfi);
2539 if (es->code == NULL)
2542 goto after_machine_frame;
2545 /* read the values for this source frame from the execution state */
2547 DOLOG( printf("recovering source state for%s:\n",
2548 (ss->frames == NULL) ? " TOPFRAME" : "");
2549 replace_replacement_point_println(rp, 1); );
2551 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2553 #if defined(ENABLE_VMLOG)
2554 vmlog_cacao_unrol_method(ss->frames->method);
2557 #if defined(REPLACE_STATISTICS)
2558 REPLACE_COUNT(stat_frames);
2560 replace_statistics_source_frame(ss->frames);
2563 /* in locked areas (below native frames), identity map the frame */
2566 ss->frames->torp = ss->frames->fromrp;
2567 ss->frames->tocode = ss->frames->fromcode;
2570 /* unroll to the next (outer) frame */
2573 /* this frame is in inlined code */
2575 DOLOG( printf("INLINED!\n"); );
2579 assert(rp->type == RPLPOINT_TYPE_INLINE);
2580 REPLACE_COUNT(stat_unroll_inline);
2583 /* this frame had been called at machine-level. pop it. */
2585 DOLOG( printf("UNWIND\n"); );
2587 ra = replace_pop_activation_record(es, ss->frames);
2589 DOLOG( printf("REACHED NATIVE CODE\n"); );
2593 #if !defined(ENABLE_GC_CACAO)
2594 break; /* XXX remove to activate native frames */
2599 /* find the replacement point at the call site */
2601 after_machine_frame:
2602 rp = replace_find_replacement_point_for_pc(es->code, es->pc, 0);
2605 vm_abort("could not find replacement point while unrolling call");
2607 DOLOG( printf("found replacement point.\n");
2608 replace_replacement_point_println(rp, 1); );
2610 assert(rp->type == RPLPOINT_TYPE_CALL);
2611 REPLACE_COUNT(stat_unroll_call);
2613 } /* end loop over source frames */
2615 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2621 /* replace_map_source_state ****************************************************
2623 Map each source frame in the given source state to a target replacement
2624 point and compilation unit. If no valid code is available for a source
2625 frame, it is (re)compiled.
2628 ss...............the source state
2631 ss...............the source state, modified: The `torp` and `tocode`
2632 fields of each source frame are set.
2635 true.............everything went ok
2636 false............an exception has been thrown
2638 *******************************************************************************/
2640 static bool replace_map_source_state(sourcestate_t *ss)
2642 sourceframe_t *frame;
2645 rplpoint *parent; /* parent of inlined rplpoint */
2646 #if defined(REPLACE_STATISTICS)
2653 /* iterate over the source frames from outermost to innermost */
2655 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2657 /* XXX skip native frames */
2659 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2664 /* map frames which are not already mapped */
2666 if (frame->tocode) {
2667 code = frame->tocode;
2672 assert(frame->torp == NULL);
2674 if (parent == NULL) {
2675 /* find code for this frame */
2677 #if defined(REPLACE_STATISTICS)
2678 oldcode = frame->method->code;
2680 /* request optimization of hot methods and their callers */
2682 if (frame->method->hitcountdown < 0
2683 || (frame->down && frame->down->method->hitcountdown < 0))
2684 jit_request_optimization(frame->method);
2686 code = jit_get_current_code(frame->method);
2689 return false; /* exception */
2691 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2696 /* map this frame */
2698 rp = replace_find_replacement_point(code, frame, parent);
2700 frame->tocode = code;
2704 if (rp->type == RPLPOINT_TYPE_CALL) {
2717 /* replace_map_source_state_identity *******************************************
2719 Map each source frame in the given source state to the same replacement
2720 point and compilation unit it was derived from. This is mainly used for
2724 ss...............the source state
2727 ss...............the source state, modified: The `torp` and `tocode`
2728 fields of each source frame are set.
2730 *******************************************************************************/
2732 #if defined(ENABLE_GC_CACAO)
2733 static void replace_map_source_state_identity(sourcestate_t *ss)
2735 sourceframe_t *frame;
2737 /* iterate over the source frames from outermost to innermost */
2739 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2741 /* skip native frames */
2743 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2747 /* map frames using the identity mapping */
2749 if (frame->tocode) {
2750 assert(frame->tocode == frame->fromcode);
2751 assert(frame->torp == frame->fromrp);
2753 assert(frame->tocode == NULL);
2754 assert(frame->torp == NULL);
2755 frame->tocode = frame->fromcode;
2756 frame->torp = frame->fromrp;
2763 /* replace_build_execution_state ***********************************************
2765 Build an execution state for the given (mapped) source state.
2767 !!! CAUTION: This function rewrites the machine stack !!!
2769 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2772 ss...............the source state. Must have been mapped by
2773 replace_map_source_state before.
2774 es...............the base execution state on which to build
2777 *es..............the new execution state
2779 *******************************************************************************/
2781 static void replace_build_execution_state(sourcestate_t *ss,
2782 executionstate_t *es)
2785 sourceframe_t *prevframe;
2792 while (ss->frames) {
2794 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2795 prevframe = ss->frames;
2796 replace_push_native_frame(es, ss);
2802 if (parent == NULL) {
2803 /* create a machine-level stack frame */
2805 DOLOG( printf("pushing activation record for:\n");
2806 if (rp) replace_replacement_point_println(rp, 1);
2807 else printf("\tfirst frame\n"); );
2809 replace_push_activation_record(es, rp, prevframe, ss->frames);
2811 DOLOG( executionstate_println(es); );
2814 rp = ss->frames->torp;
2817 DOLOG( printf("creating execution state for%s:\n",
2818 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2819 replace_replacement_point_println(ss->frames->fromrp, 1);
2820 replace_replacement_point_println(rp, 1); );
2822 es->code = ss->frames->tocode;
2823 prevframe = ss->frames;
2825 #if defined(ENABLE_VMLOG)
2826 vmlog_cacao_rerol_method(ss->frames->method);
2829 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2831 DOLOG( executionstate_println(es); );
2833 if (rp->type == RPLPOINT_TYPE_CALL) {
2844 /* replace_me ******************************************************************
2846 This function is called by the signal handler when a thread reaches
2847 a replacement point. `replace_me` must map the execution state to the
2848 target replacement point and let execution continue there.
2850 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2853 rp...............replacement point that has been reached
2854 es...............execution state read by signal handler
2856 *******************************************************************************/
2858 static void replace_me(rplpoint *rp, executionstate_t *es)
2860 stackframeinfo_t *sfi;
2862 sourceframe_t *frame;
2865 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2866 threadobject *thread;
2870 origcode = es->code;
2873 #if defined(ENABLE_TLH)
2874 /*printf("Replacing in %s/%s\n", rp->method->clazz->name->text, rp->method->name->text);*/
2877 /*if (strcmp(rp->method->clazz->name->text, "antlr/AlternativeElement") == 0 && strcmp(rp->method->name->text, "getAutoGenType") ==0) opt_TraceReplacement = 2; else opt_TraceReplacement = 0;*/
2879 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2880 stat_replacements, (void*)THREADOBJECT,
2882 method_println(es->code->m); );
2884 DOLOG( replace_replacement_point_println(rp, 1); );
2886 REPLACE_COUNT(stat_replacements);
2888 /* mark start of dump memory area */
2892 /* Get the stackframeinfo for the current thread. */
2894 sfi = threads_get_current_stackframeinfo();
2896 /* recover source state */
2898 ss = replace_recover_source_state(rp, sfi, es);
2900 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2901 /* if there is a collection pending, we assume the replacement point should
2902 suspend this thread */
2906 thread = THREADOBJECT;
2908 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2910 /* map the sourcestate using the identity mapping */
2911 replace_map_source_state_identity(ss);
2913 /* since we enter the same method again, we turn off rps now */
2914 /* XXX michi: can we really do this? what if the rp was active before
2915 we activated it for the gc? */
2916 replace_deactivate_replacement_points(origcode);
2918 /* remember executionstate and sourcestate for this thread */
2919 GC_EXECUTIONSTATE = es;
2920 GC_SOURCESTATE = ss;
2922 /* really suspend this thread now (PC = 0) */
2923 threads_suspend_ack(NULL, NULL);
2925 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2928 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2930 /* map the source state */
2932 if (!replace_map_source_state(ss))
2933 vm_abort("exception during method replacement");
2935 DOLOG( replace_sourcestate_println(ss); );
2937 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2939 #if !defined(NDEBUG)
2940 /* avoid infinite loops by self-replacement, only if not in testing mode */
2942 if (!opt_TestReplacement) {
2945 frame = frame->down;
2947 if (frame->torp == origrp) {
2949 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2951 replace_deactivate_replacement_points(origcode);
2956 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2960 /* build the new execution state */
2962 replace_build_execution_state(ss, es);
2964 #if !defined(NDEBUG)
2965 /* continue execution after patched machine code, if testing mode enabled */
2967 if (opt_TestReplacement)
2968 es->pc += REPLACEMENT_PATCH_SIZE;
2971 /* release dump area */
2977 /* replace_me_wrapper **********************************************************
2979 This function is called by the signal handler. It determines if there
2980 is an active replacement point pending at the given PC and returns
2983 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2986 pc...............the program counter that triggered the replacement.
2987 context..........the context (machine state) to which the
2988 replacement should be applied.
2991 context..........the context after replacement finished.
2994 true.............replacement done, everything went ok
2995 false............no replacement done, context unchanged
2997 *******************************************************************************/
2999 bool replace_me_wrapper(u1 *pc, void *context)
3003 executionstate_t es;
3004 #if defined(ENABLE_RT_TIMING)
3005 struct timespec time_start, time_end;
3008 /* search the codeinfo for the given PC */
3010 code = code_find_codeinfo_for_pc(pc);
3013 /* search for a replacement point at the given PC */
3015 rp = replace_find_replacement_point_for_pc(code, pc, (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN));
3017 /* check if the replacement point belongs to given PC and is active */
3019 if ((rp != NULL) && (rp->pc == pc)
3020 && (rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))) {
3022 DOLOG( printf("valid replacement point\n"); );
3024 #if !defined(NDEBUG)
3025 executionstate_sanity_check(context);
3028 /* set codeinfo pointer in execution state */
3032 /* read execution state from current context */
3034 md_executionstate_read(&es, context);
3036 DOLOG( printf("REPLACEMENT READ: ");
3037 executionstate_println(&es); );
3039 /* do the actual replacement */
3041 #if defined(ENABLE_RT_TIMING)
3042 RT_TIMING_GET_TIME(time_start);
3045 replace_me(rp, &es);
3047 #if defined(ENABLE_RT_TIMING)
3048 RT_TIMING_GET_TIME(time_end);
3049 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_REPLACE);
3052 /* write execution state to current context */
3054 md_executionstate_write(&es, context);
3056 DOLOG( printf("REPLACEMENT WRITE: ");
3057 executionstate_println(&es); );
3059 /* new code is entered after returning */
3061 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
3069 /******************************************************************************/
3070 /* NOTE: Stuff specific to the exact GC is below. */
3071 /******************************************************************************/
3073 #if defined(ENABLE_GC_CACAO)
3074 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
3076 stackframeinfo_t *sfi;
3077 executionstate_t *es;
3080 /* Get the stackframeinfo of this thread. */
3082 assert(thread == THREADOBJECT);
3084 sfi = threads_get_current_stackframeinfo();
3086 /* create the execution state */
3087 es = DNEW(executionstate_t);
3090 es->pv = 0; /* since we are in a native, PV is invalid! */
3091 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
3093 /* we assume we are in a native (no replacement point)! */
3094 ss = replace_recover_source_state(NULL, sfi, es);
3096 /* map the sourcestate using the identity mapping */
3097 replace_map_source_state_identity(ss);
3099 /* remember executionstate and sourcestate for this thread */
3100 GC_EXECUTIONSTATE = es;
3101 GC_SOURCESTATE = ss;
3105 #if defined(ENABLE_GC_CACAO)
3106 void replace_gc_into_native(threadobject *thread)
3108 executionstate_t *es;
3111 /* get the executionstate and sourcestate for the given thread */
3112 es = GC_EXECUTIONSTATE;
3113 ss = GC_SOURCESTATE;
3115 /* rebuild the stack of the given thread */
3116 replace_build_execution_state(ss, es);
3121 /******************************************************************************/
3122 /* NOTE: No important code below. */
3123 /******************************************************************************/
3126 /* statistics *****************************************************************/
3128 #if defined(REPLACE_STATISTICS)
3129 static void print_freq(FILE *file,int *array,int limit)
3134 for (i=0; i<limit; ++i)
3136 sum += array[limit];
3137 for (i=0; i<limit; ++i) {
3139 fprintf(file," %3d: %8d (cum %3d%%)\n",
3140 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3142 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3144 #endif /* defined(REPLACE_STATISTICS) */
3147 #if defined(REPLACE_STATISTICS)
3149 #define REPLACE_PRINT_DIST(name, array) \
3150 printf(" " name " distribution:\n"); \
3151 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3153 void replace_print_statistics(void)
3155 printf("replacement statistics:\n");
3156 printf(" # of replacements: %d\n", stat_replacements);
3157 printf(" # of frames: %d\n", stat_frames);
3158 printf(" # of recompilations: %d\n", stat_recompile);
3159 printf(" patched static calls:%d\n", stat_staticpatch);
3160 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3161 printf(" unrolled calls: %d\n", stat_unroll_call);
3162 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3163 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3164 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3165 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3166 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3167 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3168 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3169 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3170 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3171 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3173 printf(" # of methods: %d\n", stat_methods);
3174 printf(" # of replacement points: %d\n", stat_rploints);
3175 printf(" # of regallocs: %d\n", stat_regallocs);
3176 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3177 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3178 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3182 #endif /* defined(REPLACE_STATISTICS) */
3185 #if defined(REPLACE_STATISTICS)
3186 static void replace_statistics_source_frame(sourceframe_t *frame)
3195 for (i=0; i<frame->javalocalcount; ++i) {
3196 switch (frame->javalocaltype[i]) {
3197 case TYPE_ADR: adr++; break;
3198 case TYPE_RET: ret++; break;
3199 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3200 case TYPE_VOID: vd++; break;
3205 REPLACE_COUNT_DIST(stat_dist_locals, n);
3206 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3207 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3208 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3209 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3210 adr = ret = prim = n = 0;
3211 for (i=0; i<frame->javastackdepth; ++i) {
3212 switch (frame->javastacktype[i]) {
3213 case TYPE_ADR: adr++; break;
3214 case TYPE_RET: ret++; break;
3215 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3219 REPLACE_COUNT_DIST(stat_dist_stack, n);
3220 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3221 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3222 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3224 #endif /* defined(REPLACE_STATISTICS) */
3227 /* debugging helpers **********************************************************/
3229 /* replace_replacement_point_println *******************************************
3231 Print replacement point info.
3234 rp...............the replacement point to print
3236 *******************************************************************************/
3238 #if !defined(NDEBUG)
3240 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3242 static const char *replace_type_str[] = {
3252 void replace_replacement_point_println(rplpoint *rp, int depth)
3258 printf("(rplpoint *)NULL\n");
3262 for (j=0; j<depth; ++j)
3265 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3266 rp->id, (void*)rp,rp->pc,rp->callsize,
3267 replace_type_str[rp->type]);
3268 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3270 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3271 printf(" COUNTDOWN");
3272 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3274 printf(" parent:%p\n", (void*)rp->parent);
3275 for (j=0; j<depth; ++j)
3277 printf("ra:%d = [", rp->regalloccount);
3279 for (j=0; j<rp->regalloccount; ++j) {
3282 index = rp->regalloc[j].index;
3284 case RPLALLOC_STACK: printf("S"); break;
3285 case RPLALLOC_PARAM: printf("P"); break;
3286 case RPLALLOC_SYNC : printf("Y"); break;
3287 default: printf("%d", index);
3289 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3290 if (rp->regalloc[j].type == TYPE_RET) {
3291 printf("ret(L%03d)", rp->regalloc[j].regoff);
3294 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3299 for (j=0; j<depth; ++j)
3302 method_print(rp->method);
3306 #endif /* !defined(NDEBUG) */
3309 /* replace_show_replacement_points *********************************************
3311 Print replacement point info.
3314 code.............codeinfo whose replacement points should be printed.
3316 *******************************************************************************/
3318 #if !defined(NDEBUG)
3319 void replace_show_replacement_points(codeinfo *code)
3327 printf("(codeinfo *)NULL\n");
3331 printf("\treplacement points: %d\n",code->rplpointcount);
3333 printf("\ttotal allocations : %d\n",code->regalloccount);
3334 printf("\tsaved int regs : %d\n",code->savedintcount);
3335 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3336 #if defined(HAS_ADDRESS_REGISTER_FILE)
3337 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3339 printf("\tmemuse : %d\n",code->memuse);
3343 for (i=0; i<code->rplpointcount; ++i) {
3344 rp = code->rplpoints + i;
3347 parent = rp->parent;
3350 parent = parent->parent;
3352 replace_replacement_point_println(rp, depth);
3358 #if !defined(NDEBUG)
3359 static void java_value_print(s4 type, replace_val_t value)
3364 printf("%016llx",(unsigned long long) value.l);
3366 if (type < 0 || type > TYPE_RET)
3367 printf(" <INVALID TYPE:%d>", type);
3369 printf(" %s", show_jit_type_names[type]);
3371 if (type == TYPE_ADR && value.a != NULL) {
3374 utf_display_printable_ascii_classname(obj->vftbl->clazz->name);
3376 if (obj->vftbl->clazz == class_java_lang_String) {
3378 u = javastring_toutf(obj, false);
3379 utf_display_printable_ascii(u);
3383 else if (type == TYPE_INT) {
3384 printf(" %ld", (long) value.i);
3386 else if (type == TYPE_LNG) {
3387 printf(" %lld", (long long) value.l);
3389 else if (type == TYPE_FLT) {
3390 printf(" %f", value.f);
3392 else if (type == TYPE_DBL) {
3393 printf(" %f", value.d);
3396 #endif /* !defined(NDEBUG) */
3399 #if !defined(NDEBUG)
3400 void replace_source_frame_println(sourceframe_t *frame)
3405 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3406 printf("\tNATIVE\n");
3407 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3408 printf("\tnativepc: %p\n", frame->nativepc);
3409 printf("\tframesize: %d\n", frame->nativeframesize);
3412 for (i=0; i<INT_REG_CNT; ++i) {
3413 if (nregdescint[i] == REG_SAV)
3414 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3418 for (i=0; i<FLT_REG_CNT; ++i) {
3419 if (nregdescfloat[i] == REG_SAV)
3420 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3428 method_println(frame->method);
3429 printf("\tid: %d\n", frame->id);
3430 printf("\ttype: %s\n", replace_type_str[frame->type]);
3433 if (frame->instance.a) {
3434 printf("\tinstance: ");
3435 java_value_print(TYPE_ADR, frame->instance);
3439 if (frame->javalocalcount) {
3440 printf("\tlocals (%d):\n",frame->javalocalcount);
3441 for (i=0; i<frame->javalocalcount; ++i) {
3442 t = frame->javalocaltype[i];
3443 if (t == TYPE_VOID) {
3444 printf("\tlocal[ %2d] = void\n",i);
3447 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3448 java_value_print(t, frame->javalocals[i]);
3455 if (frame->javastackdepth) {
3456 printf("\tstack (depth %d):\n",frame->javastackdepth);
3457 for (i=0; i<frame->javastackdepth; ++i) {
3458 t = frame->javastacktype[i];
3459 if (t == TYPE_VOID) {
3460 printf("\tstack[%2d] = void", i);
3463 printf("\tstack[%2d] = ",i);
3464 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3471 if (frame->syncslotcount) {
3472 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3473 for (i=0; i<frame->syncslotcount; ++i) {
3474 printf("\tslot[%2d] = ",i);
3475 #ifdef HAS_4BYTE_STACKSLOT
3476 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3478 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3484 if (frame->fromcode) {
3485 printf("\tfrom %p ", (void*)frame->fromcode);
3486 method_println(frame->fromcode->m);
3488 if (frame->tocode) {
3489 printf("\tto %p ", (void*)frame->tocode);
3490 method_println(frame->tocode->m);
3493 if (frame->fromrp) {
3494 printf("\tfrom replacement point:\n");
3495 replace_replacement_point_println(frame->fromrp, 2);
3498 printf("\tto replacement point:\n");
3499 replace_replacement_point_println(frame->torp, 2);
3504 #endif /* !defined(NDEBUG) */
3507 /* replace_sourcestate_println *************************************************
3512 ss...............the source state to print
3514 *******************************************************************************/
3516 #if !defined(NDEBUG)
3517 void replace_sourcestate_println(sourcestate_t *ss)
3520 sourceframe_t *frame;
3523 printf("(sourcestate_t *)NULL\n");
3527 printf("sourcestate_t:\n");
3529 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3530 printf(" frame %d:\n", i);
3531 replace_source_frame_println(frame);
3537 /* replace_sourcestate_println_short *******************************************
3539 Print a compact representation of the given source state.
3542 ss...............the source state to print
3544 *******************************************************************************/
3546 #if !defined(NDEBUG)
3547 void replace_sourcestate_println_short(sourcestate_t *ss)
3549 sourceframe_t *frame;
3551 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3554 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3555 printf("NATIVE (pc %p size %d) ",
3556 (void*)frame->nativepc, frame->nativeframesize);
3557 replace_stackframeinfo_println(frame->sfi);
3562 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3565 printf("%s", replace_type_str[frame->fromrp->type]);
3567 if (frame->torp && frame->torp->type != frame->fromrp->type)
3568 printf("->%s", replace_type_str[frame->torp->type]);
3570 if (frame->tocode != frame->fromcode)
3571 printf(" (%p->%p/%d) ",
3572 (void*) frame->fromcode, (void*) frame->tocode,
3575 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3577 method_println(frame->method);
3582 #if !defined(NDEBUG)
3583 static void replace_stackframeinfo_println(stackframeinfo_t *sfi)
3585 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3586 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3587 (void*)sfi->ra, (void*)sfi->xpc);
3590 method_println(sfi->code->m);
3598 * These are local overrides for various environment variables in Emacs.
3599 * Please do not remove this and leave it at the end of the file, where
3600 * Emacs will automagically detect them.
3601 * ---------------------------------------------------------------------
3604 * indent-tabs-mode: t
3608 * vim:noexpandtab:sw=4:ts=4: