1 /* src/vm/jit/replace.c - 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
35 #if defined(ENABLE_GC_CACAO)
36 # include "mm/cacao-gc/gc.h"
39 #include "mm/memory.h"
41 #include "threads/thread.h"
43 #include "toolbox/logging.h"
45 #include "vm/stringlocal.h"
47 #include "vm/jit/abi.h"
48 #include "vm/jit/asmpart.h"
49 #include "vm/jit/disass.h"
50 #include "vm/jit/executionstate.h"
51 #include "vm/jit/jit.h"
52 #include "vm/jit/methodheader.h"
53 #include "vm/jit/replace.h"
54 #include "vm/jit/show.h"
55 #include "vm/jit/stack.h"
57 #include "vmcore/options.h"
58 #include "vmcore/classcache.h"
59 #if defined(ENABLE_RT_TIMING)
60 #include "vmcore/rt-timing.h"
63 #define REPLACE_PATCH_DYNAMIC_CALL
64 /*#define REPLACE_PATCH_ALL*/
66 #if defined(ENABLE_VMLOG)
67 #include <vmlog_cacao.h>
70 /*** architecture-dependent configuration *************************************/
72 /* first unset the macros (default) */
73 #undef REPLACE_RA_BETWEEN_FRAMES
74 #undef REPLACE_RA_TOP_OF_FRAME
75 #undef REPLACE_RA_LINKAGE_AREA
76 #undef REPLACE_LEAFMETHODS_RA_REGISTER
78 /* i386, x86_64 and m68k */
79 #if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
80 #define REPLACE_RA_BETWEEN_FRAMES
82 #elif defined(__ALPHA__)
83 #define REPLACE_RA_TOP_OF_FRAME
84 #define REPLACE_LEAFMETHODS_RA_REGISTER
86 #elif defined(__POWERPC__)
87 #define REPLACE_RA_LINKAGE_AREA
88 #define REPLACE_LEAFMETHODS_RA_REGISTER
90 #elif defined(__S390__)
91 #define REPLACE_RA_TOP_OF_FRAME
95 /*** configuration of native stack slot size **********************************/
97 /* XXX this should be in md-abi.h files, probably */
99 #if defined(HAS_4BYTE_STACKSLOT)
100 #define SIZE_OF_STACKSLOT 4
101 #define STACK_SLOTS_PER_FLOAT 2
102 typedef u4 stackslot_t;
104 #define SIZE_OF_STACKSLOT 8
105 #define STACK_SLOTS_PER_FLOAT 1
106 typedef u8 stackslot_t;
110 /*** debugging ****************************************************************/
113 static void java_value_print(s4 type, replace_val_t value);
114 static void replace_stackframeinfo_println(stackframeinfo_t *sfi);
118 #define DOLOG(code) do{ if (opt_TraceReplacement > 1) { code; } } while(0)
119 #define DOLOG_SHORT(code) do{ if (opt_TraceReplacement > 0) { code; } } while(0)
122 #define DOLOG_SHORT(code)
126 /*** statistics ***************************************************************/
128 #define REPLACE_STATISTICS
130 #if defined(REPLACE_STATISTICS)
132 static int stat_replacements = 0;
133 static int stat_frames = 0;
134 static int stat_recompile = 0;
135 static int stat_staticpatch = 0;
136 static int stat_unroll_inline = 0;
137 static int stat_unroll_call = 0;
138 static int stat_dist_frames[20] = { 0 };
139 static int stat_dist_locals[20] = { 0 };
140 static int stat_dist_locals_adr[10] = { 0 };
141 static int stat_dist_locals_prim[10] = { 0 };
142 static int stat_dist_locals_ret[10] = { 0 };
143 static int stat_dist_locals_void[10] = { 0 };
144 static int stat_dist_stack[10] = { 0 };
145 static int stat_dist_stack_adr[10] = { 0 };
146 static int stat_dist_stack_prim[10] = { 0 };
147 static int stat_dist_stack_ret[10] = { 0 };
148 static int stat_methods = 0;
149 static int stat_rploints = 0;
150 static int stat_regallocs = 0;
151 static int stat_dist_method_rplpoints[20] = { 0 };
153 #define REPLACE_COUNT(cnt) (cnt)++
154 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
155 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
157 #define REPLACE_COUNT_DIST(array, val) \
159 int limit = (sizeof(array) / sizeof(int)) - 1; \
160 if ((val) < (limit)) (array)[val]++; \
161 else (array)[limit]++; \
164 static void replace_statistics_source_frame(sourceframe_t *frame);
168 #define REPLACE_COUNT(cnt)
169 #define REPLACE_COUNT_IF(cnt, cond)
170 #define REPLACE_COUNT_INC(cnt, inc)
171 #define REPLACE_COUNT_DIST(array, val)
173 #endif /* defined(REPLACE_STATISTICS) */
176 /*** constants used internally ************************************************/
178 #define TOP_IS_NORMAL 0
179 #define TOP_IS_ON_STACK 1
180 #define TOP_IS_IN_ITMP1 2
181 #define TOP_IS_VOID 3
184 /******************************************************************************/
185 /* PART I: Creating / freeing replacement points */
186 /******************************************************************************/
189 /* replace_create_replacement_point ********************************************
191 Create a replacement point.
194 jd...............current jitdata
195 iinfo............inlining info for the current position
196 rp...............pre-allocated (uninitialized) rplpoint
197 type.............RPLPOINT_TYPE constant
198 iptr.............current instruction
199 *pra.............current rplalloc pointer
200 javalocals.......the javalocals at the current point
201 stackvars........the stack variables at the current point
202 stackdepth.......the stack depth at the current point
203 paramcount.......number of parameters at the start of stackvars
206 *rpa.............points to the next free rplalloc
208 *******************************************************************************/
210 static void replace_create_replacement_point(jitdata *jd,
211 insinfo_inline *iinfo,
228 REPLACE_COUNT(stat_rploints);
230 rp->method = (iinfo) ? iinfo->method : jd->m;
231 rp->pc = NULL; /* set by codegen */
232 rp->callsize = 0; /* set by codegen */
236 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
238 /* XXX unify these two fields */
239 rp->parent = (iinfo) ? iinfo->rp : NULL;
241 /* store local allocation info of javalocals */
244 for (i = 0; i < rp->method->maxlocals; ++i) {
245 index = javalocals[i];
252 ra->flags = v->flags & (INMEMORY);
253 ra->regoff = v->vv.regoff;
257 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
265 /* store allocation info of java stack vars */
267 for (i = 0; i < stackdepth; ++i) {
268 v = VAR(stackvars[i]);
269 ra->flags = v->flags & (INMEMORY);
270 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
272 /* XXX how to handle locals on the stack containing returnAddresses? */
273 if (v->type == TYPE_RET) {
274 assert(stackvars[i] >= jd->localcount);
275 ra->regoff = v->vv.retaddr->nr;
278 ra->regoff = v->vv.regoff;
282 /* total number of allocations */
284 rp->regalloccount = ra - rp->regalloc;
290 /* replace_create_inline_start_replacement_point *******************************
292 Create an INLINE_START replacement point.
295 jd...............current jitdata
296 rp...............pre-allocated (uninitialized) rplpoint
297 iptr.............current instruction
298 *pra.............current rplalloc pointer
299 javalocals.......the javalocals at the current point
302 *rpa.............points to the next free rplalloc
305 the insinfo_inline * for the following inlined body
307 *******************************************************************************/
309 static insinfo_inline * replace_create_inline_start_replacement_point(
316 insinfo_inline *calleeinfo;
319 calleeinfo = iptr->sx.s23.s3.inlineinfo;
323 replace_create_replacement_point(jd, calleeinfo->parent, rp,
324 RPLPOINT_TYPE_INLINE, iptr, pra,
326 calleeinfo->stackvars, calleeinfo->stackvarscount,
327 calleeinfo->paramcount);
329 if (calleeinfo->synclocal != UNUSED) {
331 ra->index = RPLALLOC_SYNC;
332 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
333 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
343 /* replace_create_replacement_points *******************************************
345 Create the replacement points for the given code.
348 jd...............current jitdata, must not have any replacement points
351 code->rplpoints.......set to the list of replacement points
352 code->rplpointcount...number of replacement points
353 code->regalloc........list of allocation info
354 code->regalloccount...total length of allocation info list
355 code->globalcount.....number of global allocations at the
356 start of code->regalloc
359 true.............everything ok
360 false............an exception has been thrown
362 *******************************************************************************/
364 #define CLEAR_javalocals(array, method) \
366 for (i=0; i<(method)->maxlocals; ++i) \
367 (array)[i] = UNUSED; \
370 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
372 if ((array) != NULL) \
373 MCOPY((dest), (array), s4, (method)->maxlocals); \
375 CLEAR_javalocals((dest), (method)); \
378 #define COUNT_javalocals(array, method, counter) \
380 for (i=0; i<(method)->maxlocals; ++i) \
381 if ((array)[i] != UNUSED) \
385 bool replace_create_replacement_points(jitdata *jd)
403 insinfo_inline *iinfo;
406 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
410 REPLACE_COUNT(stat_methods);
412 /* get required compiler data */
417 /* assert that we wont overwrite already allocated data */
421 assert(code->rplpoints == NULL);
422 assert(code->rplpointcount == 0);
423 assert(code->regalloc == NULL);
424 assert(code->regalloccount == 0);
425 assert(code->globalcount == 0);
429 /* in instance methods, we may need a rplpoint at the method entry */
431 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
432 if (!(m->flags & ACC_STATIC)) {
433 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
439 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
441 /* iterate over the basic block list to find replacement points */
446 javalocals = DMNEW(s4, jd->maxlocals);
448 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
452 if (bptr->flags < BBFINISHED)
455 /* get info about this block */
458 iinfo = bptr->inlineinfo;
460 /* initialize javalocals at the start of this block */
462 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
464 /* iterate over the instructions */
467 iend = iptr + bptr->icount;
471 for (; iptr != iend; ++iptr) {
473 #if defined(ENABLE_GC_CACAO)
475 md = iptr->sx.s23.s3.bte->md;
477 COUNT_javalocals(javalocals, m, alloccount);
478 alloccount += iptr->s1.argcount;
480 alloccount -= iinfo->throughcount;
484 case ICMD_INVOKESTATIC:
485 case ICMD_INVOKESPECIAL:
486 case ICMD_INVOKEVIRTUAL:
487 case ICMD_INVOKEINTERFACE:
488 INSTRUCTION_GET_METHODDESC(iptr, md);
490 COUNT_javalocals(javalocals, m, alloccount);
491 alloccount += iptr->s1.argcount;
493 alloccount -= iinfo->throughcount;
501 stack_javalocals_store(iptr, javalocals);
515 case ICMD_INLINE_START:
516 iinfo = iptr->sx.s23.s3.inlineinfo;
519 COUNT_javalocals(javalocals, m, alloccount);
520 alloccount += iinfo->stackvarscount;
521 if (iinfo->synclocal != UNUSED)
525 /* javalocals may be set at next block start, or now */
526 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
529 case ICMD_INLINE_BODY:
530 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
532 jl = iinfo->javalocals_start;
534 /* get the javalocals from the following block start */
536 jl = bptr->next->javalocals;
539 COUNT_javalocals(jl, m, alloccount);
542 case ICMD_INLINE_END:
543 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
544 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
545 iinfo = iptr->sx.s23.s3.inlineinfo;
547 if (iinfo->javalocals_end)
548 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
549 iinfo = iinfo->parent;
553 if (iptr == bptr->iinstr)
555 } /* end instruction loop */
557 /* create replacement points at targets of backward branches */
558 /* We only need the replacement point there, if there is no */
559 /* replacement point inside the block. */
561 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
562 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
563 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
567 if (test > startcount) {
568 /* we don't need an extra rplpoint */
569 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
573 alloccount += bptr->indepth;
574 if (bptr->inlineinfo)
575 alloccount -= bptr->inlineinfo->throughcount;
577 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
581 } /* end basicblock loop */
583 /* if no points were found, there's nothing to do */
588 /* allocate replacement point array and allocation array */
590 rplpoints = MNEW(rplpoint, count);
591 regalloc = MNEW(rplalloc, alloccount);
594 /* initialize replacement point structs */
598 /* XXX try to share code with the counting loop! */
600 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
603 if (bptr->flags < BBFINISHED)
606 /* get info about this block */
609 iinfo = bptr->inlineinfo;
611 /* initialize javalocals at the start of this block */
613 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
615 /* create replacement points at targets of backward branches */
617 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
619 i = (iinfo) ? iinfo->throughcount : 0;
620 replace_create_replacement_point(jd, iinfo, rp++,
621 bptr->type, bptr->iinstr, &ra,
622 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
624 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
625 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
628 /* iterate over the instructions */
631 iend = iptr + bptr->icount;
633 for (; iptr != iend; ++iptr) {
635 #if defined(ENABLE_GC_CACAO)
637 md = iptr->sx.s23.s3.bte->md;
639 i = (iinfo) ? iinfo->throughcount : 0;
640 replace_create_replacement_point(jd, iinfo, rp++,
641 RPLPOINT_TYPE_CALL, iptr, &ra,
642 javalocals, iptr->sx.s23.s2.args,
643 iptr->s1.argcount - i,
648 case ICMD_INVOKESTATIC:
649 case ICMD_INVOKESPECIAL:
650 case ICMD_INVOKEVIRTUAL:
651 case ICMD_INVOKEINTERFACE:
652 INSTRUCTION_GET_METHODDESC(iptr, md);
654 i = (iinfo) ? iinfo->throughcount : 0;
655 replace_create_replacement_point(jd, iinfo, rp++,
656 RPLPOINT_TYPE_CALL, iptr, &ra,
657 javalocals, iptr->sx.s23.s2.args,
658 iptr->s1.argcount - i,
667 stack_javalocals_store(iptr, javalocals);
675 replace_create_replacement_point(jd, iinfo, rp++,
676 RPLPOINT_TYPE_RETURN, iptr, &ra,
677 NULL, &(iptr->s1.varindex), 1, 0);
681 replace_create_replacement_point(jd, iinfo, rp++,
682 RPLPOINT_TYPE_RETURN, iptr, &ra,
686 case ICMD_INLINE_START:
687 iinfo = replace_create_inline_start_replacement_point(
688 jd, rp++, iptr, &ra, javalocals);
690 /* javalocals may be set at next block start, or now */
691 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
694 case ICMD_INLINE_BODY:
695 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
697 jl = iinfo->javalocals_start;
699 /* get the javalocals from the following block start */
701 jl = bptr->next->javalocals;
703 /* create a non-trappable rplpoint */
704 replace_create_replacement_point(jd, iinfo, rp++,
705 RPLPOINT_TYPE_BODY, iptr, &ra,
707 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
710 case ICMD_INLINE_END:
711 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
712 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
713 iinfo = iptr->sx.s23.s3.inlineinfo;
715 if (iinfo->javalocals_end)
716 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
717 iinfo = iinfo->parent;
720 } /* end instruction loop */
721 } /* end basicblock loop */
723 assert((rp - rplpoints) == count);
724 assert((ra - regalloc) == alloccount);
726 /* store the data in the codeinfo */
728 code->rplpoints = rplpoints;
729 code->rplpointcount = count;
730 code->regalloc = regalloc;
731 code->regalloccount = alloccount;
732 code->globalcount = 0;
733 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
734 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
735 #if defined(HAS_ADDRESS_REGISTER_FILE)
736 code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
738 code->memuse = rd->memuse;
739 code->stackframesize = jd->cd->stackframesize;
741 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
742 REPLACE_COUNT_INC(stat_regallocs, alloccount);
744 /* everything alright */
750 /* replace_free_replacement_points *********************************************
752 Free memory used by replacement points.
755 code.............codeinfo whose replacement points should be freed.
757 *******************************************************************************/
759 void replace_free_replacement_points(codeinfo *code)
764 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
767 MFREE(code->regalloc,rplalloc,code->regalloccount);
769 code->rplpoints = NULL;
770 code->rplpointcount = 0;
771 code->regalloc = NULL;
772 code->regalloccount = 0;
773 code->globalcount = 0;
777 /******************************************************************************/
778 /* PART II: Activating / deactivating replacement points */
779 /******************************************************************************/
782 /* replace_activate_replacement_points *****************************************
784 Activate the replacement points of the given compilation unit. When this
785 function returns, the replacement points are "armed", so each thread
786 reaching one of the points will enter the replacement mechanism.
789 code.............codeinfo of which replacement points should be
791 mappable.........if true, only mappable replacement points are
794 *******************************************************************************/
796 void replace_activate_replacement_points(codeinfo *code, bool mappable)
803 assert(code->savedmcode == NULL);
805 /* count trappable replacement points */
808 i = code->rplpointcount;
809 rp = code->rplpoints;
811 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
814 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
820 /* allocate buffer for saved machine code */
822 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
823 code->savedmcode = savedmcode;
824 savedmcode += count * REPLACEMENT_PATCH_SIZE;
826 /* activate trappable replacement points */
827 /* (in reverse order to handle overlapping points within basic blocks) */
829 i = code->rplpointcount;
830 rp = code->rplpoints + i;
832 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
834 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
837 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
840 DOLOG( printf("activate replacement point:\n");
841 replace_replacement_point_println(rp, 1); fflush(stdout); );
843 savedmcode -= REPLACEMENT_PATCH_SIZE;
845 #if defined(ENABLE_JIT)
846 # if defined(ENABLE_DISASSEMBLER)
847 DOLOG( printf("\tinstruction before: ");
848 disassinstr(rp->pc); fflush(stdout); );
851 md_patch_replacement_point(rp->pc, savedmcode, false);
853 # if defined(ENABLE_DISASSEMBLER)
854 DOLOG( printf("\tinstruction after : ");
855 disassinstr(rp->pc); fflush(stdout); );
859 rp->flags |= RPLPOINT_FLAG_ACTIVE;
862 assert(savedmcode == code->savedmcode);
866 /* replace_deactivate_replacement_points ***************************************
868 Deactivate a replacement points in the given compilation unit.
869 When this function returns, the replacement points will be "un-armed",
870 that is a each thread reaching a point will just continue normally.
873 code.............the compilation unit
875 *******************************************************************************/
877 void replace_deactivate_replacement_points(codeinfo *code)
884 if (code->savedmcode == NULL) {
885 /* disarm countdown points by patching the branches */
887 i = code->rplpointcount;
888 rp = code->rplpoints;
890 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
891 == RPLPOINT_FLAG_COUNTDOWN)
894 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
901 assert(code->savedmcode != NULL);
902 savedmcode = code->savedmcode;
904 /* de-activate each trappable replacement point */
906 i = code->rplpointcount;
907 rp = code->rplpoints;
910 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
915 DOLOG( printf("deactivate replacement point:\n");
916 replace_replacement_point_println(rp, 1); fflush(stdout); );
918 #if defined(ENABLE_JIT)
919 # if defined(ENABLE_DISASSEMBLER)
920 DOLOG( printf("\tinstruction before: ");
921 disassinstr(rp->pc); fflush(stdout); );
924 md_patch_replacement_point(rp->pc, savedmcode, true);
926 # if defined(ENABLE_DISASSEMBLER)
927 DOLOG( printf("\tinstruction before: ");
928 disassinstr(rp->pc); fflush(stdout); );
932 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
934 savedmcode += REPLACEMENT_PATCH_SIZE;
937 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
939 /* free saved machine code */
941 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
942 code->savedmcode = NULL;
946 /******************************************************************************/
947 /* PART III: The replacement mechanism */
948 /******************************************************************************/
951 /* replace_read_value **********************************************************
953 Read a value with the given allocation from the execution state.
956 es...............execution state
957 ra...............allocation
958 javaval..........where to put the value
961 *javaval.........the value
963 *******************************************************************************/
965 static void replace_read_value(executionstate_t *es,
967 replace_val_t *javaval)
969 if (ra->flags & INMEMORY) {
970 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
971 #ifdef HAS_4BYTE_STACKSLOT
972 if (IS_2_WORD_TYPE(ra->type)) {
973 javaval->l = *(u8*)(es->sp + ra->regoff);
977 javaval->p = *(ptrint*)(es->sp + ra->regoff);
978 #ifdef HAS_4BYTE_STACKSLOT
983 /* allocated register */
984 if (IS_FLT_DBL_TYPE(ra->type)) {
985 javaval->d = es->fltregs[ra->regoff];
987 if (ra->type == TYPE_FLT)
988 javaval->f = javaval->d;
990 #if defined(HAS_ADDRESS_REGISTER_FILE)
991 else if (IS_ADR_TYPE(ra->type)) {
992 javaval->p = es->adrregs[ra->regoff];
996 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
997 if (ra->type == TYPE_LNG) {
998 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
999 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
1002 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
1003 javaval->p = es->intregs[ra->regoff];
1009 /* replace_write_value *********************************************************
1011 Write a value to the given allocation in the execution state.
1014 es...............execution state
1015 ra...............allocation
1016 *javaval.........the value
1018 *******************************************************************************/
1020 static void replace_write_value(executionstate_t *es,
1022 replace_val_t *javaval)
1024 if (ra->flags & INMEMORY) {
1025 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1026 #ifdef HAS_4BYTE_STACKSLOT
1027 if (IS_2_WORD_TYPE(ra->type)) {
1028 *(u8*)(es->sp + ra->regoff) = javaval->l;
1032 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1033 #ifdef HAS_4BYTE_STACKSLOT
1038 /* allocated register */
1041 es->fltregs[ra->regoff] = (double) javaval->f;
1044 es->fltregs[ra->regoff] = javaval->d;
1046 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1048 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1049 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1052 #if defined(HAS_ADDRESS_REGISTER_FILE)
1054 es->adrregs[ra->regoff] = javaval->p;
1057 es->intregs[ra->regoff] = javaval->p;
1063 /* replace_new_sourceframe *****************************************************
1065 Allocate a new source frame and insert it at the front of the frame list.
1068 ss...............the source state
1071 ss->frames.......set to new frame (the new head of the frame list).
1074 returns the new frame
1076 *******************************************************************************/
1078 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1080 sourceframe_t *frame;
1082 frame = DNEW(sourceframe_t);
1083 MZERO(frame, sourceframe_t, 1);
1085 frame->down = ss->frames;
1092 /* replace_read_executionstate *************************************************
1094 Read a source frame from the given executions state.
1095 The new source frame is pushed to the front of the frame list of the
1099 rp...............replacement point at which `es` was taken
1100 es...............execution state
1101 ss...............the source state to add the source frame to
1102 topframe.........true, if the first (top-most) source frame on the
1106 *ss..............the source state with the newly created source frame
1109 *******************************************************************************/
1111 static s4 replace_normalize_type_map[] = {
1112 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1113 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1114 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1115 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1116 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1117 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1118 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1122 static void replace_read_executionstate(rplpoint *rp,
1123 executionstate_t *es,
1132 sourceframe_t *frame;
1135 stackslot_t *basesp;
1137 code = code_find_codeinfo_for_pc(rp->pc);
1139 topslot = TOP_IS_NORMAL;
1143 sp = (stackslot_t *) es->sp;
1145 /* in some cases the top stack slot is passed in REG_ITMP1 */
1147 if (rp->type == BBTYPE_EXH) {
1148 topslot = TOP_IS_IN_ITMP1;
1151 /* calculate base stack pointer */
1153 basesp = sp + code->stackframesize;
1155 /* create the source frame */
1157 frame = replace_new_sourceframe(ss);
1158 frame->method = rp->method;
1160 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1161 frame->type = replace_normalize_type_map[rp->type];
1163 frame->fromcode = code;
1165 /* read local variables */
1167 count = m->maxlocals;
1168 frame->javalocalcount = count;
1169 frame->javalocals = DMNEW(replace_val_t, count);
1170 frame->javalocaltype = DMNEW(u1, count);
1172 /* mark values as undefined */
1173 for (i=0; i<count; ++i) {
1174 #if !defined(NDEBUG)
1175 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1177 frame->javalocaltype[i] = TYPE_VOID;
1180 /* some entries in the intregs array are not meaningful */
1181 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1182 #if !defined(NDEBUG)
1183 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1185 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1187 #endif /* !defined(NDEBUG) */
1189 /* read javalocals */
1191 count = rp->regalloccount;
1194 while (count && (i = ra->index) >= 0) {
1195 assert(i < m->maxlocals);
1196 frame->javalocaltype[i] = ra->type;
1197 if (ra->type == TYPE_RET)
1198 frame->javalocals[i].i = ra->regoff;
1200 replace_read_value(es, ra, frame->javalocals + i);
1205 /* read instance, if this is the first rplpoint */
1207 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1208 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1210 /* we are at the start of the method body, so if local 0 is set, */
1211 /* it is the instance. */
1212 if (frame->javalocaltype[0] == TYPE_ADR)
1213 frame->instance = frame->javalocals[0];
1218 md = rp->method->parseddesc;
1220 assert(md->paramcount >= 1);
1221 instra.type = TYPE_ADR;
1222 instra.regoff = md->params[0].regoff;
1223 if (md->params[0].inmemory) {
1224 instra.flags = INMEMORY;
1225 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1230 replace_read_value(es, &instra, &(frame->instance));
1233 #if defined(__I386__)
1234 else if (!(rp->method->flags & ACC_STATIC)) {
1235 /* On i386 we always pass the first argument on stack. */
1236 frame->instance.a = *(java_object_t **)(basesp + 1);
1239 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1241 /* read stack slots */
1243 frame->javastackdepth = count;
1244 frame->javastack = DMNEW(replace_val_t, count);
1245 frame->javastacktype = DMNEW(u1, count);
1247 #if !defined(NDEBUG)
1248 /* mark values as undefined */
1249 for (i=0; i<count; ++i) {
1250 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1251 frame->javastacktype[i] = TYPE_VOID;
1253 #endif /* !defined(NDEBUG) */
1257 /* the first stack slot is special in SBR and EXH blocks */
1259 if (topslot == TOP_IS_ON_STACK) {
1262 assert(ra->index == RPLALLOC_STACK);
1263 assert(ra->type == TYPE_ADR);
1264 frame->javastack[i].p = sp[-1];
1265 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1270 else if (topslot == TOP_IS_IN_ITMP1) {
1273 assert(ra->index == RPLALLOC_STACK);
1274 assert(ra->type == TYPE_ADR);
1275 frame->javastack[i].p = es->intregs[REG_ITMP1];
1276 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1281 else if (topslot == TOP_IS_VOID) {
1284 assert(ra->index == RPLALLOC_STACK);
1285 frame->javastack[i].l = 0;
1286 frame->javastacktype[i] = TYPE_VOID;
1292 /* read remaining stack slots */
1294 for (; count--; ra++) {
1295 if (ra->index == RPLALLOC_SYNC) {
1296 assert(rp->type == RPLPOINT_TYPE_INLINE);
1298 /* only read synchronization slots when traversing an inline point */
1301 sourceframe_t *calleeframe = frame->down;
1302 assert(calleeframe);
1303 assert(calleeframe->syncslotcount == 0);
1304 assert(calleeframe->syncslots == NULL);
1306 calleeframe->syncslotcount = 1;
1307 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1308 replace_read_value(es,ra,calleeframe->syncslots);
1311 frame->javastackdepth--;
1315 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1317 /* do not read parameters of calls down the call chain */
1319 if (!topframe && ra->index == RPLALLOC_PARAM) {
1320 frame->javastackdepth--;
1323 if (ra->type == TYPE_RET)
1324 frame->javastack[i].i = ra->regoff;
1326 replace_read_value(es,ra,frame->javastack + i);
1327 frame->javastacktype[i] = ra->type;
1334 /* replace_write_executionstate ************************************************
1336 Pop a source frame from the front of the frame list of the given source state
1337 and write its values into the execution state.
1340 rp...............replacement point for which execution state should be
1342 es...............the execution state to modify
1343 ss...............the given source state
1344 topframe.........true, if this is the last (top-most) source frame to be
1348 *es..............the execution state derived from the source state
1350 *******************************************************************************/
1352 static void replace_write_executionstate(rplpoint *rp,
1353 executionstate_t *es,
1362 sourceframe_t *frame;
1365 stackslot_t *basesp;
1367 code = code_find_codeinfo_for_pc(rp->pc);
1369 topslot = TOP_IS_NORMAL;
1371 /* pop a source frame */
1375 ss->frames = frame->down;
1377 /* calculate stack pointer */
1379 sp = (stackslot_t *) es->sp;
1381 basesp = sp + code->stackframesize;
1383 /* in some cases the top stack slot is passed in REG_ITMP1 */
1385 if (rp->type == BBTYPE_EXH) {
1386 topslot = TOP_IS_IN_ITMP1;
1389 /* write javalocals */
1392 count = rp->regalloccount;
1394 while (count && (i = ra->index) >= 0) {
1395 assert(i < m->maxlocals);
1396 assert(i < frame->javalocalcount);
1397 assert(ra->type == frame->javalocaltype[i]);
1398 if (ra->type == TYPE_RET) {
1399 /* XXX assert that it matches this rplpoint */
1402 replace_write_value(es, ra, frame->javalocals + i);
1407 /* write stack slots */
1411 /* the first stack slot is special in SBR and EXH blocks */
1413 if (topslot == TOP_IS_ON_STACK) {
1416 assert(ra->index == RPLALLOC_STACK);
1417 assert(i < frame->javastackdepth);
1418 assert(frame->javastacktype[i] == TYPE_ADR);
1419 sp[-1] = frame->javastack[i].p;
1424 else if (topslot == TOP_IS_IN_ITMP1) {
1427 assert(ra->index == RPLALLOC_STACK);
1428 assert(i < frame->javastackdepth);
1429 assert(frame->javastacktype[i] == TYPE_ADR);
1430 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1435 else if (topslot == TOP_IS_VOID) {
1438 assert(ra->index == RPLALLOC_STACK);
1439 assert(i < frame->javastackdepth);
1440 assert(frame->javastacktype[i] == TYPE_VOID);
1446 /* write remaining stack slots */
1448 for (; count--; ra++) {
1449 if (ra->index == RPLALLOC_SYNC) {
1450 assert(rp->type == RPLPOINT_TYPE_INLINE);
1452 /* only write synchronization slots when traversing an inline point */
1455 assert(frame->down);
1456 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1457 assert(frame->down->syncslots != NULL);
1459 replace_write_value(es,ra,frame->down->syncslots);
1464 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1466 /* do not write parameters of calls down the call chain */
1468 if (!topframe && ra->index == RPLALLOC_PARAM) {
1471 ra->index = RPLALLOC_PARAM;
1474 replace_write_value(es,ra,&v);
1478 assert(i < frame->javastackdepth);
1479 assert(ra->type == frame->javastacktype[i]);
1480 if (ra->type == TYPE_RET) {
1481 /* XXX assert that it matches this rplpoint */
1484 replace_write_value(es,ra,frame->javastack + i);
1496 /* md_pop_stackframe ***********************************************************
1498 Restore callee-saved registers (including the RA register),
1499 set the stack pointer to the next stackframe,
1500 set the PC to the return address of the popped frame.
1502 *** This function imitates the effects of the method epilog ***
1503 *** and returning from the method call. ***
1506 es...............execution state
1509 *es..............the execution state after popping the stack frame
1510 NOTE: es->code and es->pv are NOT updated.
1512 *******************************************************************************/
1514 void md_pop_stackframe(executionstate_t *es)
1520 stackslot_t *basesp;
1525 /* alignment offset of RA */
1528 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1529 if (es->code->stackframesize)
1530 ra_align_off = SIZE_OF_STACKSLOT - SIZEOF_VOID_P;
1533 /* read the return address */
1535 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1536 if (code_is_leafmethod(es->code))
1540 ra = md_stacktrace_get_returnaddress(es->sp,
1541 SIZE_OF_STACKSLOT * es->code->stackframesize + ra_align_off);
1543 /* calculate the base of the stack frame */
1545 sp = (stackslot_t *) es->sp;
1546 basesp = sp + es->code->stackframesize;
1548 /* restore return address, if part of frame */
1550 #if defined(REPLACE_RA_TOP_OF_FRAME)
1551 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1552 if (!code_is_leafmethod(es->code))
1554 es->ra = (u1*) (ptrint) *--basesp;
1555 #endif /* REPLACE_RA_TOP_OF_FRAME */
1557 #if defined(REPLACE_RA_LINKAGE_AREA)
1558 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1559 if (!code_is_leafmethod(es->code))
1561 es->ra = (u1*) (ptrint) basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1562 #endif /* REPLACE_RA_LINKAGE_AREA */
1564 /* restore saved int registers */
1567 for (i=0; i<es->code->savedintcount; ++i) {
1568 while (nregdescint[--reg] != REG_SAV)
1570 es->intregs[reg] = *--basesp;
1573 /* restore saved flt registers */
1577 for (i=0; i<es->code->savedfltcount; ++i) {
1578 while (nregdescfloat[--reg] != REG_SAV)
1580 basesp -= STACK_SLOTS_PER_FLOAT;
1581 es->fltregs[reg] = *(double*)basesp;
1584 #if defined(HAS_ADDRESS_REGISTER_FILE)
1585 /* restore saved adr registers */
1588 for (i=0; i<es->code->savedadrcount; ++i) {
1589 while (nregdescadr[--reg] != REG_SAV)
1591 es->adrregs[reg] = *--basesp;
1595 /* adjust the stackpointer */
1597 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1599 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1600 es->sp += ra_align_off + SIZEOF_VOID_P; /* skip return address */
1603 /* set the program counter to the return address */
1607 /* in debugging mode clobber non-saved registers */
1609 #if !defined(NDEBUG)
1611 for (i=0; i<INT_REG_CNT; ++i)
1612 if (nregdescint[i] != REG_SAV)
1613 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1614 for (i=0; i<FLT_REG_CNT; ++i)
1615 if (nregdescfloat[i] != REG_SAV)
1616 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1617 # if defined(HAS_ADDRESS_REGISTER_FILE)
1618 for (i=0; i<ADR_REG_CNT; ++i)
1619 if (nregdescadr[i] != REG_SAV)
1620 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1622 #endif /* !defined(NDEBUG) */
1626 /* md_push_stackframe **********************************************************
1628 Save the given return address, build the new stackframe,
1629 and store callee-saved registers.
1631 *** This function imitates the effects of a call and the ***
1632 *** method prolog of the callee. ***
1635 es...............execution state
1636 calleecode.......the code we are "calling"
1637 ra...............the return address to save
1640 *es..............the execution state after pushing the stack frame
1641 NOTE: es->pc, es->code, and es->pv are NOT updated.
1643 *******************************************************************************/
1645 void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra)
1649 stackslot_t *basesp;
1655 /* write the return address */
1657 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1658 es->sp -= SIZEOF_VOID_P;
1659 *((void **)es->sp) = (void *) ra;
1660 if (calleecode->stackframesize)
1661 es->sp -= (SIZE_OF_STACKSLOT - SIZEOF_VOID_P);
1662 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1664 es->ra = (u1*) (ptrint) ra;
1666 /* build the stackframe */
1668 DOLOG( printf("building stackframe of %d words at %p\n",
1669 calleecode->stackframesize, (void*)es->sp); );
1671 sp = (stackslot_t *) es->sp;
1674 sp -= calleecode->stackframesize;
1677 /* in debug mode, invalidate stack frame first */
1679 /* XXX may not invalidate linkage area used by native code! */
1681 #if !defined(NDEBUG) && 0
1682 for (i=0; i< (basesp - sp) && i < 1; ++i) {
1683 sp[i] = 0xdeaddeadU;
1687 #if defined(__I386__)
1688 /* Stackslot 0 may contain the object instance for vftbl patching.
1689 Destroy it, so there's no undefined value used. */
1690 if ((basesp - sp) > 0) {
1695 /* save the return address register */
1697 #if defined(REPLACE_RA_TOP_OF_FRAME)
1698 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1699 if (!code_is_leafmethod(calleecode))
1701 *--basesp = (ptrint) ra;
1702 #endif /* REPLACE_RA_TOP_OF_FRAME */
1704 #if defined(REPLACE_RA_LINKAGE_AREA)
1705 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1706 if (!code_is_leafmethod(calleecode))
1708 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1709 #endif /* REPLACE_RA_LINKAGE_AREA */
1711 /* save int registers */
1714 for (i=0; i<calleecode->savedintcount; ++i) {
1715 while (nregdescint[--reg] != REG_SAV)
1717 *--basesp = es->intregs[reg];
1719 /* XXX may not clobber saved regs used by native code! */
1720 #if !defined(NDEBUG) && 0
1721 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1725 /* save flt registers */
1729 for (i=0; i<calleecode->savedfltcount; ++i) {
1730 while (nregdescfloat[--reg] != REG_SAV)
1732 basesp -= STACK_SLOTS_PER_FLOAT;
1733 *(double*)basesp = es->fltregs[reg];
1735 /* XXX may not clobber saved regs used by native code! */
1736 #if !defined(NDEBUG) && 0
1737 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1741 #if defined(HAS_ADDRESS_REGISTER_FILE)
1742 /* save adr registers */
1745 for (i=0; i<calleecode->savedadrcount; ++i) {
1746 while (nregdescadr[--reg] != REG_SAV)
1748 *--basesp = es->adrregs[reg];
1750 /* XXX may not clobber saved regs used by native code! */
1751 #if !defined(NDEBUG) && 0
1752 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1759 /* replace_pop_activation_record ***********************************************
1761 Peel a stack frame from the execution state.
1763 *** This function imitates the effects of the method epilog ***
1764 *** and returning from the method call. ***
1767 es...............execution state
1768 frame............source frame, receives synchronization slots
1771 *es..............the execution state after popping the stack frame
1774 the return address of the poped activation record
1776 *******************************************************************************/
1778 u1* replace_pop_activation_record(executionstate_t *es,
1779 sourceframe_t *frame)
1791 /* calculate the base of the stack frame */
1793 sp = (stackslot_t *) es->sp;
1794 assert(frame->syncslotcount == 0);
1795 assert(frame->syncslots == NULL);
1796 count = code_get_sync_slot_count(es->code);
1797 frame->syncslotcount = count;
1798 frame->syncslots = DMNEW(replace_val_t, count);
1799 for (i=0; i<count; ++i) {
1800 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX md_ function */
1803 /* pop the stackframe */
1805 md_pop_stackframe(es);
1809 DOLOG( printf("RA = %p\n", (void*)ra); );
1811 /* Subtract one from the PC so we do not hit the replacement point */
1812 /* of the instruction following the call, if there is one. */
1816 /* find the new codeinfo */
1818 pv = md_codegen_get_pv_from_pc(ra);
1819 DOLOG( printf("PV = %p\n", (void*) pv); );
1821 code = code_get_codeinfo_for_pv(pv);
1822 DOLOG( printf("CODE = %p\n", (void*) code); );
1824 /* return NULL if we reached native code */
1829 return (code) ? ra : NULL;
1833 /* replace_patch_method_pointer ************************************************
1835 Patch a method pointer (may be in code, data segment, vftbl, or interface
1839 mpp..............address of the method pointer to patch
1840 entrypoint.......the new entrypoint of the method
1841 kind.............kind of call to patch, used only for debugging
1843 *******************************************************************************/
1845 static void replace_patch_method_pointer(methodptr *mpp,
1846 methodptr entrypoint,
1849 #if !defined(NDEBUG)
1854 DOLOG( printf("patch method pointer from: %p to %p\n",
1855 (void*) *mpp, (void*)entrypoint); );
1857 #if !defined(NDEBUG)
1858 oldcode = code_get_codeinfo_for_pv(*mpp);
1859 newcode = code_get_codeinfo_for_pv(entrypoint);
1861 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1862 method_println(oldcode->m);
1863 printf("\t with %p ", (void*) newcode);
1864 method_println(newcode->m); );
1866 assert(oldcode->m == newcode->m);
1869 /* write the new entrypoint */
1871 *mpp = (methodptr) entrypoint;
1875 /* replace_patch_class *********************************************************
1877 Patch a method in the given class.
1880 vftbl............vftbl of the class
1881 m................the method to patch
1882 oldentrypoint....the old entrypoint to replace
1883 entrypoint.......the new entrypoint
1885 *******************************************************************************/
1887 void replace_patch_class(vftbl_t *vftbl,
1896 /* patch the vftbl of the class */
1898 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1902 /* patch the interface tables */
1904 assert(oldentrypoint);
1906 for (i=0; i < vftbl->interfacetablelength; ++i) {
1907 mpp = vftbl->interfacetable[-i];
1908 mppend = mpp + vftbl->interfacevftbllength[i];
1909 for (; mpp != mppend; ++mpp)
1910 if (*mpp == oldentrypoint) {
1911 replace_patch_method_pointer(mpp, entrypoint, "interface");
1917 /* replace_patch_class_hierarchy ***********************************************
1919 Patch a method in all loaded classes.
1922 m................the method to patch
1923 oldentrypoint....the old entrypoint to replace
1924 entrypoint.......the new entrypoint
1926 *******************************************************************************/
1928 struct replace_patch_data_t {
1934 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1936 vftbl_t *vftbl = c->vftbl;
1939 && vftbl->vftbllength > pd->m->vftblindex
1940 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1941 && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
1943 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1947 void replace_patch_class_hierarchy(methodinfo *m,
1951 struct replace_patch_data_t pd;
1954 pd.oldentrypoint = oldentrypoint;
1955 pd.entrypoint = entrypoint;
1957 DOLOG_SHORT( printf("patching class hierarchy: ");
1958 method_println(m); );
1960 classcache_foreach_loaded_class(
1961 (classcache_foreach_functionptr_t) &replace_patch_callback,
1966 /* replace_patch_future_calls **************************************************
1968 Analyse a call site and depending on the kind of call patch the call, the
1969 virtual function table, or the interface table.
1972 ra...............return address pointing after the call site
1973 callerframe......source frame of the caller
1974 calleeframe......source frame of the callee, must have been mapped
1976 *******************************************************************************/
1978 void replace_patch_future_calls(u1 *ra,
1979 sourceframe_t *callerframe,
1980 sourceframe_t *calleeframe)
1983 methodptr entrypoint;
1984 methodptr oldentrypoint;
1987 codeinfo *calleecode;
1988 methodinfo *calleem;
1993 assert(callerframe->down == calleeframe);
1995 /* get the new codeinfo and the method that shall be entered */
1997 calleecode = calleeframe->tocode;
2000 calleem = calleeframe->method;
2001 assert(calleem == calleecode->m);
2003 entrypoint = (methodptr) calleecode->entrypoint;
2005 /* check if we are at an method entry rplpoint at the innermost frame */
2007 atentry = (calleeframe->down == NULL)
2008 && !(calleem->flags & ACC_STATIC)
2009 && (calleeframe->fromrp->id == 0); /* XXX */
2011 /* get the position to patch, in case it was a statically bound call */
2013 pv = callerframe->fromcode->entrypoint;
2014 patchpos = md_jit_method_patch_address(pv, ra, NULL);
2016 if (patchpos == NULL) {
2017 /* the call was dispatched dynamically */
2019 /* we can only patch such calls if we are at the entry point */
2021 #if !defined(__I386__)
2022 /* On i386 we always know the instance argument. */
2027 assert((calleem->flags & ACC_STATIC) == 0);
2029 oldentrypoint = calleeframe->fromcode->entrypoint;
2031 /* we need to know the instance */
2033 if (!calleeframe->instance.a) {
2034 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
2035 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
2041 obj = calleeframe->instance.a;
2044 assert(vftbl->clazz->vftbl == vftbl);
2046 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->clazz); );
2048 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
2051 /* the call was statically bound */
2053 #if defined(__I386__)
2054 /* It happens that there is a patcher trap. (pm) */
2055 if (*(u2 *)(patchpos - 1) == 0x0b0f) {
2058 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
2063 /* replace_push_activation_record **********************************************
2065 Push a stack frame onto the execution state.
2067 *** This function imitates the effects of a call and the ***
2068 *** method prolog of the callee. ***
2071 es...............execution state
2072 rpcall...........the replacement point at the call site
2073 callerframe......source frame of the caller, or NULL for creating the
2075 calleeframe......source frame of the callee, must have been mapped
2078 *es..............the execution state after pushing the stack frame
2080 *******************************************************************************/
2082 void replace_push_activation_record(executionstate_t *es,
2084 sourceframe_t *callerframe,
2085 sourceframe_t *calleeframe)
2091 codeinfo *calleecode;
2094 assert(!rpcall || callerframe);
2095 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
2096 assert(!rpcall || rpcall == callerframe->torp);
2097 assert(calleeframe);
2098 assert(!callerframe || calleeframe == callerframe->down);
2100 /* the compilation unit we are entering */
2102 calleecode = calleeframe->tocode;
2105 /* calculate the return address */
2108 ra = rpcall->pc + rpcall->callsize;
2110 ra = es->pc + 1 /* XXX this is ugly */;
2112 /* push the stackframe */
2114 md_push_stackframe(es, calleecode, ra);
2116 /* we move into a new code unit, set code, PC, PV */
2118 es->code = calleecode;
2119 es->pc = calleecode->entrypoint; /* XXX not needed? */
2120 es->pv = calleecode->entrypoint;
2122 /* write slots used for synchronization */
2124 sp = (stackslot_t *) es->sp;
2125 count = code_get_sync_slot_count(calleecode);
2126 assert(count == calleeframe->syncslotcount);
2127 for (i=0; i<count; ++i) {
2128 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2131 /* redirect future invocations */
2133 if (callerframe && rpcall) {
2134 #if defined(REPLACE_PATCH_ALL)
2135 if (rpcall->type == callerframe->fromrp->type)
2137 if (rpcall == callerframe->fromrp)
2139 replace_patch_future_calls(ra, callerframe, calleeframe);
2144 /* replace_find_replacement_point **********************************************
2146 Find the replacement point in the given code corresponding to the
2147 position given in the source frame.
2150 code.............the codeinfo in which to search the rplpoint
2151 frame............the source frame defining the position to look for
2152 parent...........parent replacement point to match
2155 the replacement point
2157 *******************************************************************************/
2159 rplpoint * replace_find_replacement_point(codeinfo *code,
2160 sourceframe_t *frame,
2173 DOLOG( printf("searching replacement point for:\n");
2174 replace_source_frame_println(frame); );
2178 DOLOG( printf("code = %p\n", (void*)code); );
2180 rp = code->rplpoints;
2181 i = code->rplpointcount;
2183 if (rp->id == frame->id && rp->method == frame->method
2184 && rp->parent == parent
2185 && replace_normalize_type_map[rp->type] == frame->type)
2187 /* check if returnAddresses match */
2188 /* XXX optimize: only do this if JSRs in method */
2189 DOLOG( printf("checking match for:");
2190 replace_replacement_point_println(rp, 1); fflush(stdout); );
2193 for (j = rp->regalloccount; j--; ++ra) {
2194 if (ra->type == TYPE_RET) {
2195 if (ra->index == RPLALLOC_STACK) {
2196 assert(stacki < frame->javastackdepth);
2197 if (frame->javastack[stacki].i != ra->regoff)
2202 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2203 if (frame->javalocals[ra->index].i != ra->regoff)
2216 #if !defined(NDEBUG)
2217 printf("candidate replacement points were:\n");
2218 rp = code->rplpoints;
2219 i = code->rplpointcount;
2221 replace_replacement_point_println(rp, 1);
2225 vm_abort("no matching replacement point found");
2226 return NULL; /* NOT REACHED */
2230 /* replace_find_replacement_point_for_pc ***************************************
2232 Find the nearest replacement point at or before the given PC. The
2233 given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
2234 the replacement point to be found.
2237 code.............compilation unit the PC is in
2238 pc...............the machine code PC
2241 the replacement point found, or
2242 NULL if no replacement point was found
2244 *******************************************************************************/
2246 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc, unsigned desired_flags)
2252 DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
2253 method_println(code->m); );
2257 rp = code->rplpoints;
2258 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2259 DOLOG( replace_replacement_point_println(rp, 2); );
2260 if (rp->pc <= pc && rp->pc + rp->callsize >= pc) {
2261 if (desired_flags) {
2262 if (rp->flags & desired_flags) {
2274 /* replace_pop_native_frame ****************************************************
2276 Unroll a native frame in the execution state and create a source frame
2280 es...............current execution state
2281 ss...............the current source state
2282 sfi..............stackframeinfo for the native frame
2285 es...............execution state after unrolling the native frame
2286 ss...............gets the added native source frame
2288 *******************************************************************************/
2290 static void replace_pop_native_frame(executionstate_t *es,
2292 stackframeinfo_t *sfi)
2294 sourceframe_t *frame;
2300 frame = replace_new_sourceframe(ss);
2304 /* remember pc and size of native frame */
2306 frame->nativepc = es->pc;
2307 frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2308 assert(frame->nativeframesize >= 0);
2310 /* remember values of saved registers */
2313 for (i=0; i<INT_REG_CNT; ++i) {
2314 if (nregdescint[i] == REG_SAV)
2315 frame->nativesavint[j++] = es->intregs[i];
2319 for (i=0; i<FLT_REG_CNT; ++i) {
2320 if (nregdescfloat[i] == REG_SAV)
2321 frame->nativesavflt[j++] = es->fltregs[i];
2324 #if defined(HAS_ADDRESS_REGISTER_FILE)
2326 for (i=0; i<ADR_REG_CNT; ++i) {
2327 if (nregdescadr[i] == REG_SAV)
2328 frame->nativesavadr[j++] = es->adrregs[i];
2332 /* restore saved registers */
2334 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2336 for (i=0; i<INT_REG_CNT; ++i) {
2337 if (nregdescint[i] == REG_SAV)
2338 es->intregs[i] = sfi->intregs[j++];
2341 /* XXX we don't have them, yet, in the sfi, so clear them */
2343 for (i=0; i<INT_REG_CNT; ++i) {
2344 if (nregdescint[i] == REG_SAV)
2349 /* XXX we don't have float registers in the sfi, so clear them */
2351 for (i=0; i<FLT_REG_CNT; ++i) {
2352 if (nregdescfloat[i] == REG_SAV)
2353 es->fltregs[i] = 0.0;
2356 #if defined(HAS_ADDRESS_REGISTER_FILE)
2357 # if defined(ENABLE_GC_CACAO)
2359 for (i=0; i<ADR_REG_CNT; ++i) {
2360 if (nregdescadr[i] == REG_SAV)
2361 es->adrregs[i] = sfi->adrregs[j++];
2364 for (i=0; i<ADR_REG_CNT; ++i) {
2365 if (nregdescadr[i] == REG_SAV)
2371 /* restore codeinfo of the native stub */
2373 code = code_get_codeinfo_for_pv(sfi->pv);
2375 /* restore sp, pv, pc and codeinfo of the parent method */
2377 /* XXX michi: use this instead:
2378 es->sp = sfi->sp + code->stackframesize; */
2379 es->sp = sfi->sp + (*(s4 *) (sfi->pv + FrameSize));
2380 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2381 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
2383 es->pv = md_codegen_get_pv_from_pc(sfi->ra);
2384 es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2385 es->code = code_get_codeinfo_for_pv(es->pv);
2389 /* replace_push_native_frame ***************************************************
2391 Rebuild a native frame onto the execution state and remove its source frame.
2393 Note: The native frame is "rebuild" by setting fields like PC and stack
2394 pointer in the execution state accordingly. Values in the
2395 stackframeinfo may be modified, but the actual stack frame of the
2396 native code is not touched.
2399 es...............current execution state
2400 ss...............the current source state
2403 es...............execution state after re-rolling the native frame
2404 ss...............the native source frame is removed
2406 *******************************************************************************/
2408 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2410 sourceframe_t *frame;
2416 DOLOG( printf("pushing native frame\n"); );
2418 /* remove the frame from the source state */
2422 assert(REPLACE_IS_NATIVE_FRAME(frame));
2424 ss->frames = frame->down;
2426 /* skip sp for the native stub */
2428 es->sp -= (*(s4 *) (frame->sfi->pv + FrameSize));
2429 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2430 es->sp -= SIZE_OF_STACKSLOT; /* skip return address */
2433 /* assert that the native frame has not moved */
2435 assert(es->sp == frame->sfi->sp);
2437 /* update saved registers in the stackframeinfo */
2439 #if defined(ENABLE_GC_CACAO)
2441 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2442 for (i=0; i<INT_REG_CNT; ++i) {
2443 if (nregdescint[i] == REG_SAV)
2444 frame->sfi->intregs[j++] = es->intregs[i];
2447 for (i=0; i<ADR_REG_CNT; ++i) {
2448 if (nregdescadr[i] == REG_SAV)
2449 frame->sfi->adrregs[j++] = es->adrregs[i];
2453 /* XXX leave float registers untouched here */
2456 /* restore saved registers */
2459 for (i=0; i<INT_REG_CNT; ++i) {
2460 if (nregdescint[i] == REG_SAV)
2461 es->intregs[i] = frame->nativesavint[j++];
2465 for (i=0; i<FLT_REG_CNT; ++i) {
2466 if (nregdescfloat[i] == REG_SAV)
2467 es->fltregs[i] = frame->nativesavflt[j++];
2470 #if defined(HAS_ADDRESS_REGISTER_FILE)
2472 for (i=0; i<ADR_REG_CNT; ++i) {
2473 if (nregdescadr[i] == REG_SAV)
2474 es->adrregs[i] = frame->nativesavadr[j++];
2478 /* skip the native frame on the machine stack */
2480 es->sp -= frame->nativeframesize;
2482 /* set the pc the next frame must return to */
2484 es->pc = frame->nativepc;
2488 /* replace_recover_source_state ************************************************
2490 Recover the source state from the given replacement point and execution
2494 rp...............replacement point that has been reached, if any
2495 sfi..............stackframeinfo, if called from native code
2496 es...............execution state at the replacement point rp
2501 *******************************************************************************/
2503 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2504 stackframeinfo_t *sfi,
2505 executionstate_t *es)
2510 #if defined(REPLACE_STATISTICS)
2514 /* create the source frame structure in dump memory */
2516 ss = DNEW(sourcestate_t);
2519 /* each iteration of the loop recovers one source frame */
2526 DOLOG( executionstate_println(es); );
2528 /* if we are not at a replacement point, it is a native frame */
2531 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2534 replace_pop_native_frame(es, ss, sfi);
2537 if (es->code == NULL)
2540 goto after_machine_frame;
2543 /* read the values for this source frame from the execution state */
2545 DOLOG( printf("recovering source state for%s:\n",
2546 (ss->frames == NULL) ? " TOPFRAME" : "");
2547 replace_replacement_point_println(rp, 1); );
2549 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2551 #if defined(ENABLE_VMLOG)
2552 vmlog_cacao_unrol_method(ss->frames->method);
2555 #if defined(REPLACE_STATISTICS)
2556 REPLACE_COUNT(stat_frames);
2558 replace_statistics_source_frame(ss->frames);
2561 /* in locked areas (below native frames), identity map the frame */
2564 ss->frames->torp = ss->frames->fromrp;
2565 ss->frames->tocode = ss->frames->fromcode;
2568 /* unroll to the next (outer) frame */
2571 /* this frame is in inlined code */
2573 DOLOG( printf("INLINED!\n"); );
2577 assert(rp->type == RPLPOINT_TYPE_INLINE);
2578 REPLACE_COUNT(stat_unroll_inline);
2581 /* this frame had been called at machine-level. pop it. */
2583 DOLOG( printf("UNWIND\n"); );
2585 ra = replace_pop_activation_record(es, ss->frames);
2587 DOLOG( printf("REACHED NATIVE CODE\n"); );
2591 #if !defined(ENABLE_GC_CACAO)
2592 break; /* XXX remove to activate native frames */
2597 /* find the replacement point at the call site */
2599 after_machine_frame:
2600 rp = replace_find_replacement_point_for_pc(es->code, es->pc, 0);
2603 vm_abort("could not find replacement point while unrolling call");
2605 DOLOG( printf("found replacement point.\n");
2606 replace_replacement_point_println(rp, 1); );
2608 assert(rp->type == RPLPOINT_TYPE_CALL);
2609 REPLACE_COUNT(stat_unroll_call);
2611 } /* end loop over source frames */
2613 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2619 /* replace_map_source_state ****************************************************
2621 Map each source frame in the given source state to a target replacement
2622 point and compilation unit. If no valid code is available for a source
2623 frame, it is (re)compiled.
2626 ss...............the source state
2629 ss...............the source state, modified: The `torp` and `tocode`
2630 fields of each source frame are set.
2633 true.............everything went ok
2634 false............an exception has been thrown
2636 *******************************************************************************/
2638 static bool replace_map_source_state(sourcestate_t *ss)
2640 sourceframe_t *frame;
2643 rplpoint *parent; /* parent of inlined rplpoint */
2644 #if defined(REPLACE_STATISTICS)
2651 /* iterate over the source frames from outermost to innermost */
2653 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2655 /* XXX skip native frames */
2657 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2662 /* map frames which are not already mapped */
2664 if (frame->tocode) {
2665 code = frame->tocode;
2670 assert(frame->torp == NULL);
2672 if (parent == NULL) {
2673 /* find code for this frame */
2675 #if defined(REPLACE_STATISTICS)
2676 oldcode = frame->method->code;
2678 /* request optimization of hot methods and their callers */
2680 if (frame->method->hitcountdown < 0
2681 || (frame->down && frame->down->method->hitcountdown < 0))
2682 jit_request_optimization(frame->method);
2684 code = jit_get_current_code(frame->method);
2687 return false; /* exception */
2689 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2694 /* map this frame */
2696 rp = replace_find_replacement_point(code, frame, parent);
2698 frame->tocode = code;
2702 if (rp->type == RPLPOINT_TYPE_CALL) {
2715 /* replace_map_source_state_identity *******************************************
2717 Map each source frame in the given source state to the same replacement
2718 point and compilation unit it was derived from. This is mainly used for
2722 ss...............the source state
2725 ss...............the source state, modified: The `torp` and `tocode`
2726 fields of each source frame are set.
2728 *******************************************************************************/
2730 #if defined(ENABLE_GC_CACAO)
2731 static void replace_map_source_state_identity(sourcestate_t *ss)
2733 sourceframe_t *frame;
2735 /* iterate over the source frames from outermost to innermost */
2737 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2739 /* skip native frames */
2741 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2745 /* map frames using the identity mapping */
2747 if (frame->tocode) {
2748 assert(frame->tocode == frame->fromcode);
2749 assert(frame->torp == frame->fromrp);
2751 assert(frame->tocode == NULL);
2752 assert(frame->torp == NULL);
2753 frame->tocode = frame->fromcode;
2754 frame->torp = frame->fromrp;
2761 /* replace_build_execution_state ***********************************************
2763 Build an execution state for the given (mapped) source state.
2765 !!! CAUTION: This function rewrites the machine stack !!!
2767 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2770 ss...............the source state. Must have been mapped by
2771 replace_map_source_state before.
2772 es...............the base execution state on which to build
2775 *es..............the new execution state
2777 *******************************************************************************/
2779 static void replace_build_execution_state(sourcestate_t *ss,
2780 executionstate_t *es)
2783 sourceframe_t *prevframe;
2790 while (ss->frames) {
2792 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2793 prevframe = ss->frames;
2794 replace_push_native_frame(es, ss);
2800 if (parent == NULL) {
2801 /* create a machine-level stack frame */
2803 DOLOG( printf("pushing activation record for:\n");
2804 if (rp) replace_replacement_point_println(rp, 1);
2805 else printf("\tfirst frame\n"); );
2807 replace_push_activation_record(es, rp, prevframe, ss->frames);
2809 DOLOG( executionstate_println(es); );
2812 rp = ss->frames->torp;
2815 DOLOG( printf("creating execution state for%s:\n",
2816 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2817 replace_replacement_point_println(ss->frames->fromrp, 1);
2818 replace_replacement_point_println(rp, 1); );
2820 es->code = ss->frames->tocode;
2821 prevframe = ss->frames;
2823 #if defined(ENABLE_VMLOG)
2824 vmlog_cacao_rerol_method(ss->frames->method);
2827 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2829 DOLOG( executionstate_println(es); );
2831 if (rp->type == RPLPOINT_TYPE_CALL) {
2842 /* replace_me ******************************************************************
2844 This function is called by the signal handler when a thread reaches
2845 a replacement point. `replace_me` must map the execution state to the
2846 target replacement point and let execution continue there.
2848 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2851 rp...............replacement point that has been reached
2852 es...............execution state read by signal handler
2854 *******************************************************************************/
2856 static void replace_me(rplpoint *rp, executionstate_t *es)
2858 stackframeinfo_t *sfi;
2860 sourceframe_t *frame;
2863 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2864 threadobject *thread;
2868 origcode = es->code;
2871 printf("Replacing in %s/%s\n", rp->method->clazz->name->text, rp->method->name->text);
2873 /*if (strcmp(rp->method->clazz->name->text, "antlr/AlternativeElement") == 0 && strcmp(rp->method->name->text, "getAutoGenType") ==0) opt_TraceReplacement = 2; else opt_TraceReplacement = 0;*/
2875 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2876 stat_replacements, (void*)THREADOBJECT,
2878 method_println(es->code->m); );
2880 DOLOG( replace_replacement_point_println(rp, 1); );
2882 REPLACE_COUNT(stat_replacements);
2884 /* mark start of dump memory area */
2888 /* Get the stackframeinfo for the current thread. */
2890 sfi = threads_get_current_stackframeinfo();
2892 /* recover source state */
2894 ss = replace_recover_source_state(rp, sfi, es);
2896 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2897 /* if there is a collection pending, we assume the replacement point should
2898 suspend this thread */
2902 thread = THREADOBJECT;
2904 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2906 /* map the sourcestate using the identity mapping */
2907 replace_map_source_state_identity(ss);
2909 /* since we enter the same method again, we turn off rps now */
2910 /* XXX michi: can we really do this? what if the rp was active before
2911 we activated it for the gc? */
2912 replace_deactivate_replacement_points(origcode);
2914 /* remember executionstate and sourcestate for this thread */
2915 GC_EXECUTIONSTATE = es;
2916 GC_SOURCESTATE = ss;
2918 /* really suspend this thread now (PC = 0) */
2919 threads_suspend_ack(NULL, NULL);
2921 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2924 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2926 /* map the source state */
2928 if (!replace_map_source_state(ss))
2929 vm_abort("exception during method replacement");
2931 DOLOG( replace_sourcestate_println(ss); );
2933 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2935 #if !defined(NDEBUG)
2936 /* avoid infinite loops by self-replacement, only if not in testing mode */
2938 if (!opt_TestReplacement) {
2941 frame = frame->down;
2943 if (frame->torp == origrp) {
2945 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2947 replace_deactivate_replacement_points(origcode);
2952 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2956 /* build the new execution state */
2958 replace_build_execution_state(ss, es);
2960 #if !defined(NDEBUG)
2961 /* continue execution after patched machine code, if testing mode enabled */
2963 if (opt_TestReplacement)
2964 es->pc += REPLACEMENT_PATCH_SIZE;
2967 /* release dump area */
2973 /* replace_me_wrapper **********************************************************
2975 This function is called by the signal handler. It determines if there
2976 is an active replacement point pending at the given PC and returns
2979 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2982 pc...............the program counter that triggered the replacement.
2983 context..........the context (machine state) to which the
2984 replacement should be applied.
2987 context..........the context after replacement finished.
2990 true.............replacement done, everything went ok
2991 false............no replacement done, context unchanged
2993 *******************************************************************************/
2995 bool replace_me_wrapper(u1 *pc, void *context)
2999 executionstate_t es;
3000 #if defined(ENABLE_RT_TIMING)
3001 struct timespec time_start, time_end;
3004 /* search the codeinfo for the given PC */
3006 code = code_find_codeinfo_for_pc(pc);
3009 /* search for a replacement point at the given PC */
3011 rp = replace_find_replacement_point_for_pc(code, pc, (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN));
3013 /* check if the replacement point belongs to given PC and is active */
3015 if ((rp != NULL) && (rp->pc == pc)
3016 && (rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))) {
3018 DOLOG( printf("valid replacement point\n"); );
3020 #if !defined(NDEBUG)
3021 executionstate_sanity_check(context);
3024 /* set codeinfo pointer in execution state */
3028 /* read execution state from current context */
3030 md_executionstate_read(&es, context);
3032 DOLOG( printf("REPLACEMENT READ: ");
3033 executionstate_println(&es); );
3035 /* do the actual replacement */
3037 #if defined(ENABLE_RT_TIMING)
3038 RT_TIMING_GET_TIME(time_start);
3041 replace_me(rp, &es);
3043 #if defined(ENABLE_RT_TIMING)
3044 RT_TIMING_GET_TIME(time_end);
3045 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_REPLACE);
3048 /* write execution state to current context */
3050 md_executionstate_write(&es, context);
3052 DOLOG( printf("REPLACEMENT WRITE: ");
3053 executionstate_println(&es); );
3055 /* new code is entered after returning */
3057 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
3065 /******************************************************************************/
3066 /* NOTE: Stuff specific to the exact GC is below. */
3067 /******************************************************************************/
3069 #if defined(ENABLE_GC_CACAO)
3070 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
3072 stackframeinfo_t *sfi;
3073 executionstate_t *es;
3076 /* Get the stackframeinfo of this thread. */
3078 assert(thread == THREADOBJECT);
3080 sfi = threads_get_current_stackframeinfo();
3082 /* create the execution state */
3083 es = DNEW(executionstate_t);
3086 es->pv = 0; /* since we are in a native, PV is invalid! */
3087 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
3089 /* we assume we are in a native (no replacement point)! */
3090 ss = replace_recover_source_state(NULL, sfi, es);
3092 /* map the sourcestate using the identity mapping */
3093 replace_map_source_state_identity(ss);
3095 /* remember executionstate and sourcestate for this thread */
3096 GC_EXECUTIONSTATE = es;
3097 GC_SOURCESTATE = ss;
3101 #if defined(ENABLE_GC_CACAO)
3102 void replace_gc_into_native(threadobject *thread)
3104 executionstate_t *es;
3107 /* get the executionstate and sourcestate for the given thread */
3108 es = GC_EXECUTIONSTATE;
3109 ss = GC_SOURCESTATE;
3111 /* rebuild the stack of the given thread */
3112 replace_build_execution_state(ss, es);
3117 /******************************************************************************/
3118 /* NOTE: No important code below. */
3119 /******************************************************************************/
3122 /* statistics *****************************************************************/
3124 #if defined(REPLACE_STATISTICS)
3125 static void print_freq(FILE *file,int *array,int limit)
3130 for (i=0; i<limit; ++i)
3132 sum += array[limit];
3133 for (i=0; i<limit; ++i) {
3135 fprintf(file," %3d: %8d (cum %3d%%)\n",
3136 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3138 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3140 #endif /* defined(REPLACE_STATISTICS) */
3143 #if defined(REPLACE_STATISTICS)
3145 #define REPLACE_PRINT_DIST(name, array) \
3146 printf(" " name " distribution:\n"); \
3147 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3149 void replace_print_statistics(void)
3151 printf("replacement statistics:\n");
3152 printf(" # of replacements: %d\n", stat_replacements);
3153 printf(" # of frames: %d\n", stat_frames);
3154 printf(" # of recompilations: %d\n", stat_recompile);
3155 printf(" patched static calls:%d\n", stat_staticpatch);
3156 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3157 printf(" unrolled calls: %d\n", stat_unroll_call);
3158 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3159 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3160 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3161 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3162 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3163 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3164 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3165 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3166 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3167 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3169 printf(" # of methods: %d\n", stat_methods);
3170 printf(" # of replacement points: %d\n", stat_rploints);
3171 printf(" # of regallocs: %d\n", stat_regallocs);
3172 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3173 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3174 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3178 #endif /* defined(REPLACE_STATISTICS) */
3181 #if defined(REPLACE_STATISTICS)
3182 static void replace_statistics_source_frame(sourceframe_t *frame)
3191 for (i=0; i<frame->javalocalcount; ++i) {
3192 switch (frame->javalocaltype[i]) {
3193 case TYPE_ADR: adr++; break;
3194 case TYPE_RET: ret++; break;
3195 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3196 case TYPE_VOID: vd++; break;
3201 REPLACE_COUNT_DIST(stat_dist_locals, n);
3202 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3203 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3204 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3205 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3206 adr = ret = prim = n = 0;
3207 for (i=0; i<frame->javastackdepth; ++i) {
3208 switch (frame->javastacktype[i]) {
3209 case TYPE_ADR: adr++; break;
3210 case TYPE_RET: ret++; break;
3211 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3215 REPLACE_COUNT_DIST(stat_dist_stack, n);
3216 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3217 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3218 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3220 #endif /* defined(REPLACE_STATISTICS) */
3223 /* debugging helpers **********************************************************/
3225 /* replace_replacement_point_println *******************************************
3227 Print replacement point info.
3230 rp...............the replacement point to print
3232 *******************************************************************************/
3234 #if !defined(NDEBUG)
3236 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3238 static char *replace_type_str[] = {
3248 void replace_replacement_point_println(rplpoint *rp, int depth)
3254 printf("(rplpoint *)NULL\n");
3258 for (j=0; j<depth; ++j)
3261 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3262 rp->id, (void*)rp,rp->pc,rp->callsize,
3263 replace_type_str[rp->type]);
3264 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3266 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3267 printf(" COUNTDOWN");
3268 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3270 printf(" parent:%p\n", (void*)rp->parent);
3271 for (j=0; j<depth; ++j)
3273 printf("ra:%d = [", rp->regalloccount);
3275 for (j=0; j<rp->regalloccount; ++j) {
3278 index = rp->regalloc[j].index;
3280 case RPLALLOC_STACK: printf("S"); break;
3281 case RPLALLOC_PARAM: printf("P"); break;
3282 case RPLALLOC_SYNC : printf("Y"); break;
3283 default: printf("%d", index);
3285 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3286 if (rp->regalloc[j].type == TYPE_RET) {
3287 printf("ret(L%03d)", rp->regalloc[j].regoff);
3290 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3295 for (j=0; j<depth; ++j)
3298 method_print(rp->method);
3302 #endif /* !defined(NDEBUG) */
3305 /* replace_show_replacement_points *********************************************
3307 Print replacement point info.
3310 code.............codeinfo whose replacement points should be printed.
3312 *******************************************************************************/
3314 #if !defined(NDEBUG)
3315 void replace_show_replacement_points(codeinfo *code)
3323 printf("(codeinfo *)NULL\n");
3327 printf("\treplacement points: %d\n",code->rplpointcount);
3329 printf("\ttotal allocations : %d\n",code->regalloccount);
3330 printf("\tsaved int regs : %d\n",code->savedintcount);
3331 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3332 #if defined(HAS_ADDRESS_REGISTER_FILE)
3333 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3335 printf("\tmemuse : %d\n",code->memuse);
3339 for (i=0; i<code->rplpointcount; ++i) {
3340 rp = code->rplpoints + i;
3343 parent = rp->parent;
3346 parent = parent->parent;
3348 replace_replacement_point_println(rp, depth);
3354 #if !defined(NDEBUG)
3355 static void java_value_print(s4 type, replace_val_t value)
3360 printf("%016llx",(unsigned long long) value.l);
3362 if (type < 0 || type > TYPE_RET)
3363 printf(" <INVALID TYPE:%d>", type);
3365 printf(" %s", show_jit_type_names[type]);
3367 if (type == TYPE_ADR && value.a != NULL) {
3370 utf_display_printable_ascii_classname(obj->vftbl->clazz->name);
3372 if (obj->vftbl->clazz == class_java_lang_String) {
3374 u = javastring_toutf(obj, false);
3375 utf_display_printable_ascii(u);
3379 else if (type == TYPE_INT) {
3380 printf(" %ld", (long) value.i);
3382 else if (type == TYPE_LNG) {
3383 printf(" %lld", (long long) value.l);
3385 else if (type == TYPE_FLT) {
3386 printf(" %f", value.f);
3388 else if (type == TYPE_DBL) {
3389 printf(" %f", value.d);
3392 #endif /* !defined(NDEBUG) */
3395 #if !defined(NDEBUG)
3396 void replace_source_frame_println(sourceframe_t *frame)
3401 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3402 printf("\tNATIVE\n");
3403 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3404 printf("\tnativepc: %p\n", frame->nativepc);
3405 printf("\tframesize: %d\n", frame->nativeframesize);
3408 for (i=0; i<INT_REG_CNT; ++i) {
3409 if (nregdescint[i] == REG_SAV)
3410 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3414 for (i=0; i<FLT_REG_CNT; ++i) {
3415 if (nregdescfloat[i] == REG_SAV)
3416 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3424 method_println(frame->method);
3425 printf("\tid: %d\n", frame->id);
3426 printf("\ttype: %s\n", replace_type_str[frame->type]);
3429 if (frame->instance.a) {
3430 printf("\tinstance: ");
3431 java_value_print(TYPE_ADR, frame->instance);
3435 if (frame->javalocalcount) {
3436 printf("\tlocals (%d):\n",frame->javalocalcount);
3437 for (i=0; i<frame->javalocalcount; ++i) {
3438 t = frame->javalocaltype[i];
3439 if (t == TYPE_VOID) {
3440 printf("\tlocal[ %2d] = void\n",i);
3443 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3444 java_value_print(t, frame->javalocals[i]);
3451 if (frame->javastackdepth) {
3452 printf("\tstack (depth %d):\n",frame->javastackdepth);
3453 for (i=0; i<frame->javastackdepth; ++i) {
3454 t = frame->javastacktype[i];
3455 if (t == TYPE_VOID) {
3456 printf("\tstack[%2d] = void", i);
3459 printf("\tstack[%2d] = ",i);
3460 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3467 if (frame->syncslotcount) {
3468 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3469 for (i=0; i<frame->syncslotcount; ++i) {
3470 printf("\tslot[%2d] = ",i);
3471 #ifdef HAS_4BYTE_STACKSLOT
3472 printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3474 printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3480 if (frame->fromcode) {
3481 printf("\tfrom %p ", (void*)frame->fromcode);
3482 method_println(frame->fromcode->m);
3484 if (frame->tocode) {
3485 printf("\tto %p ", (void*)frame->tocode);
3486 method_println(frame->tocode->m);
3489 if (frame->fromrp) {
3490 printf("\tfrom replacement point:\n");
3491 replace_replacement_point_println(frame->fromrp, 2);
3494 printf("\tto replacement point:\n");
3495 replace_replacement_point_println(frame->torp, 2);
3500 #endif /* !defined(NDEBUG) */
3503 /* replace_sourcestate_println *************************************************
3508 ss...............the source state to print
3510 *******************************************************************************/
3512 #if !defined(NDEBUG)
3513 void replace_sourcestate_println(sourcestate_t *ss)
3516 sourceframe_t *frame;
3519 printf("(sourcestate_t *)NULL\n");
3523 printf("sourcestate_t:\n");
3525 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3526 printf(" frame %d:\n", i);
3527 replace_source_frame_println(frame);
3533 /* replace_sourcestate_println_short *******************************************
3535 Print a compact representation of the given source state.
3538 ss...............the source state to print
3540 *******************************************************************************/
3542 #if !defined(NDEBUG)
3543 void replace_sourcestate_println_short(sourcestate_t *ss)
3545 sourceframe_t *frame;
3547 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3550 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3551 printf("NATIVE (pc %p size %d) ",
3552 (void*)frame->nativepc, frame->nativeframesize);
3553 replace_stackframeinfo_println(frame->sfi);
3558 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3561 printf("%s", replace_type_str[frame->fromrp->type]);
3563 if (frame->torp && frame->torp->type != frame->fromrp->type)
3564 printf("->%s", replace_type_str[frame->torp->type]);
3566 if (frame->tocode != frame->fromcode)
3567 printf(" (%p->%p/%d) ",
3568 (void*) frame->fromcode, (void*) frame->tocode,
3571 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3573 method_println(frame->method);
3578 #if !defined(NDEBUG)
3579 static void replace_stackframeinfo_println(stackframeinfo_t *sfi)
3581 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3582 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3583 (void*)sfi->ra, (void*)sfi->xpc);
3586 method_println(sfi->code->m);
3594 * These are local overrides for various environment variables in Emacs.
3595 * Please do not remove this and leave it at the end of the file, where
3596 * Emacs will automagically detect them.
3597 * ---------------------------------------------------------------------
3600 * indent-tabs-mode: t
3604 * vim:noexpandtab:sw=4:ts=4: