1 /* src/vm/jit/replace.cpp - on-stack replacement of methods
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
36 #if defined(ENABLE_GC_CACAO)
37 # include "mm/cacao-gc/gc.h"
40 #include "mm/dumpmemory.hpp"
41 #include "mm/memory.hpp"
43 #include "threads/thread.hpp"
45 #include "toolbox/logging.hpp"
47 #include "vm/classcache.hpp"
48 #include "vm/globals.hpp"
49 #include "vm/options.h"
50 #include "vm/string.hpp"
52 #if defined(ENABLE_RT_TIMING)
53 # include "vm/rt-timing.h"
56 #include "vm/jit/abi.h"
57 #include "vm/jit/asmpart.h"
58 #include "vm/jit/disass.h"
59 #include "vm/jit/executionstate.h"
60 #include "vm/jit/jit.hpp"
61 #include "vm/jit/methodheader.h"
62 #include "vm/jit/replace.hpp"
63 #include "vm/jit/show.hpp"
64 #include "vm/jit/stack.h"
67 #define REPLACE_PATCH_DYNAMIC_CALL
68 /*#define REPLACE_PATCH_ALL*/
70 #if defined(ENABLE_VMLOG)
71 #include <vmlog_cacao.h>
74 /*** architecture-dependent configuration *************************************/
76 /* first unset the macros (default) */
77 #undef REPLACE_RA_LINKAGE_AREA
80 #if defined(__POWERPC__)
81 # define REPLACE_RA_LINKAGE_AREA
85 /*** configuration of native stack slot size **********************************/
87 /* XXX this should be in md-abi.h files, probably */
89 #define SIZE_OF_STACKSLOT 8
90 #define STACK_SLOTS_PER_FLOAT 1
91 typedef u8 stackslot_t;
94 /*** debugging ****************************************************************/
97 static void java_value_print(s4 type, replace_val_t value);
98 static void replace_stackframeinfo_println(stackframeinfo_t *sfi);
102 #define DOLOG(code) do{ if (opt_TraceReplacement > 1) { code; } } while(0)
103 #define DOLOG_SHORT(code) do{ if (opt_TraceReplacement > 0) { code; } } while(0)
106 #define DOLOG_SHORT(code)
110 /*** statistics ***************************************************************/
112 #define REPLACE_STATISTICS
114 #if defined(REPLACE_STATISTICS)
116 static int stat_replacements = 0;
117 static int stat_frames = 0;
118 static int stat_recompile = 0;
119 static int stat_staticpatch = 0;
120 static int stat_unroll_inline = 0;
121 static int stat_unroll_call = 0;
122 static int stat_dist_frames[20] = { 0 };
123 static int stat_dist_locals[20] = { 0 };
124 static int stat_dist_locals_adr[10] = { 0 };
125 static int stat_dist_locals_prim[10] = { 0 };
126 static int stat_dist_locals_ret[10] = { 0 };
127 static int stat_dist_locals_void[10] = { 0 };
128 static int stat_dist_stack[10] = { 0 };
129 static int stat_dist_stack_adr[10] = { 0 };
130 static int stat_dist_stack_prim[10] = { 0 };
131 static int stat_dist_stack_ret[10] = { 0 };
132 static int stat_methods = 0;
133 static int stat_rploints = 0;
134 static int stat_regallocs = 0;
135 static int stat_dist_method_rplpoints[20] = { 0 };
137 #define REPLACE_COUNT(cnt) (cnt)++
138 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
139 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
141 #define REPLACE_COUNT_DIST(array, val) \
143 int limit = (sizeof(array) / sizeof(int)) - 1; \
144 if ((val) < (limit)) (array)[val]++; \
145 else (array)[limit]++; \
148 static void replace_statistics_source_frame(sourceframe_t *frame);
152 #define REPLACE_COUNT(cnt)
153 #define REPLACE_COUNT_IF(cnt, cond)
154 #define REPLACE_COUNT_INC(cnt, inc)
155 #define REPLACE_COUNT_DIST(array, val)
157 #endif /* defined(REPLACE_STATISTICS) */
160 /*** constants used internally ************************************************/
162 #define TOP_IS_NORMAL 0
163 #define TOP_IS_ON_STACK 1
164 #define TOP_IS_IN_ITMP1 2
165 #define TOP_IS_VOID 3
168 /******************************************************************************/
169 /* PART I: Creating / freeing replacement points */
170 /******************************************************************************/
173 /* replace_create_replacement_point ********************************************
175 Create a replacement point.
178 jd...............current jitdata
179 iinfo............inlining info for the current position
180 rp...............pre-allocated (uninitialized) rplpoint
181 type.............RPLPOINT_TYPE constant
182 iptr.............current instruction
183 *pra.............current rplalloc pointer
184 javalocals.......the javalocals at the current point
185 stackvars........the stack variables at the current point
186 stackdepth.......the stack depth at the current point
187 paramcount.......number of parameters at the start of stackvars
190 *rpa.............points to the next free rplalloc
192 *******************************************************************************/
194 static void replace_create_replacement_point(jitdata *jd,
195 insinfo_inline *iinfo,
212 REPLACE_COUNT(stat_rploints);
214 rp->method = (iinfo) ? iinfo->method : jd->m;
215 rp->pc = NULL; /* set by codegen */
216 rp->callsize = 0; /* set by codegen */
220 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
222 /* XXX unify these two fields */
223 rp->parent = (iinfo) ? iinfo->rp : NULL;
225 /* store local allocation info of javalocals */
228 for (i = 0; i < rp->method->maxlocals; ++i) {
229 index = javalocals[i];
236 ra->flags = v->flags & (INMEMORY);
237 ra->regoff = v->vv.regoff;
241 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
249 /* store allocation info of java stack vars */
251 for (i = 0; i < stackdepth; ++i) {
252 v = VAR(stackvars[i]);
253 ra->flags = v->flags & (INMEMORY);
254 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
256 /* XXX how to handle locals on the stack containing returnAddresses? */
257 if (v->type == TYPE_RET) {
258 assert(stackvars[i] >= jd->localcount);
259 ra->regoff = v->vv.retaddr->nr;
262 ra->regoff = v->vv.regoff;
266 /* total number of allocations */
268 rp->regalloccount = ra - rp->regalloc;
274 /* replace_create_inline_start_replacement_point *******************************
276 Create an INLINE_START replacement point.
279 jd...............current jitdata
280 rp...............pre-allocated (uninitialized) rplpoint
281 iptr.............current instruction
282 *pra.............current rplalloc pointer
283 javalocals.......the javalocals at the current point
286 *rpa.............points to the next free rplalloc
289 the insinfo_inline * for the following inlined body
291 *******************************************************************************/
293 static insinfo_inline * replace_create_inline_start_replacement_point(
300 insinfo_inline *calleeinfo;
303 calleeinfo = iptr->sx.s23.s3.inlineinfo;
307 replace_create_replacement_point(jd, calleeinfo->parent, rp,
308 RPLPOINT_TYPE_INLINE, iptr, pra,
310 calleeinfo->stackvars, calleeinfo->stackvarscount,
311 calleeinfo->paramcount);
313 if (calleeinfo->synclocal != UNUSED) {
315 ra->index = RPLALLOC_SYNC;
316 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
317 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
327 /* replace_create_replacement_points *******************************************
329 Create the replacement points for the given code.
332 jd...............current jitdata, must not have any replacement points
335 code->rplpoints.......set to the list of replacement points
336 code->rplpointcount...number of replacement points
337 code->regalloc........list of allocation info
338 code->regalloccount...total length of allocation info list
339 code->globalcount.....number of global allocations at the
340 start of code->regalloc
343 true.............everything ok
344 false............an exception has been thrown
346 *******************************************************************************/
348 #define CLEAR_javalocals(array, method) \
350 for (i=0; i<(method)->maxlocals; ++i) \
351 (array)[i] = UNUSED; \
354 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
356 if ((array) != NULL) \
357 MCOPY((dest), (array), s4, (method)->maxlocals); \
359 CLEAR_javalocals((dest), (method)); \
362 #define COUNT_javalocals(array, method, counter) \
364 for (i=0; i<(method)->maxlocals; ++i) \
365 if ((array)[i] != UNUSED) \
369 bool replace_create_replacement_points(jitdata *jd)
387 insinfo_inline *iinfo;
390 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
394 REPLACE_COUNT(stat_methods);
396 /* get required compiler data */
401 /* assert that we wont overwrite already allocated data */
405 assert(code->rplpoints == NULL);
406 assert(code->rplpointcount == 0);
407 assert(code->regalloc == NULL);
408 assert(code->regalloccount == 0);
409 assert(code->globalcount == 0);
413 /* in instance methods, we may need a rplpoint at the method entry */
415 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
416 if (!(m->flags & ACC_STATIC)) {
417 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
423 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
425 /* iterate over the basic block list to find replacement points */
430 javalocals = (s4*) DumpMemory::allocate(sizeof(s4) * jd->maxlocals);
432 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
436 if (bptr->flags < BBFINISHED)
439 /* get info about this block */
442 iinfo = bptr->inlineinfo;
444 /* initialize javalocals at the start of this block */
446 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
448 /* iterate over the instructions */
451 iend = iptr + bptr->icount;
455 for (; iptr != iend; ++iptr) {
457 #if defined(ENABLE_GC_CACAO)
459 md = iptr->sx.s23.s3.bte->md;
461 COUNT_javalocals(javalocals, m, alloccount);
462 alloccount += iptr->s1.argcount;
464 alloccount -= iinfo->throughcount;
468 case ICMD_INVOKESTATIC:
469 case ICMD_INVOKESPECIAL:
470 case ICMD_INVOKEVIRTUAL:
471 case ICMD_INVOKEINTERFACE:
472 INSTRUCTION_GET_METHODDESC(iptr, md);
474 COUNT_javalocals(javalocals, m, alloccount);
475 alloccount += iptr->s1.argcount;
477 alloccount -= iinfo->throughcount;
485 stack_javalocals_store(iptr, javalocals);
499 case ICMD_INLINE_START:
500 iinfo = iptr->sx.s23.s3.inlineinfo;
503 COUNT_javalocals(javalocals, m, alloccount);
504 alloccount += iinfo->stackvarscount;
505 if (iinfo->synclocal != UNUSED)
509 /* javalocals may be set at next block start, or now */
510 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
513 case ICMD_INLINE_BODY:
514 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
516 jl = iinfo->javalocals_start;
518 /* get the javalocals from the following block start */
520 jl = bptr->next->javalocals;
523 COUNT_javalocals(jl, m, alloccount);
526 case ICMD_INLINE_END:
527 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
528 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
529 iinfo = iptr->sx.s23.s3.inlineinfo;
531 if (iinfo->javalocals_end)
532 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
533 iinfo = iinfo->parent;
537 if (iptr == bptr->iinstr)
539 } /* end instruction loop */
541 /* create replacement points at targets of backward branches */
542 /* We only need the replacement point there, if there is no */
543 /* replacement point inside the block. */
545 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
546 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
547 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
551 if (test > startcount) {
552 /* we don't need an extra rplpoint */
553 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
557 alloccount += bptr->indepth;
558 if (bptr->inlineinfo)
559 alloccount -= bptr->inlineinfo->throughcount;
561 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
565 } /* end basicblock loop */
567 /* if no points were found, there's nothing to do */
572 /* allocate replacement point array and allocation array */
574 rplpoints = MNEW(rplpoint, count);
575 regalloc = MNEW(rplalloc, alloccount);
578 /* initialize replacement point structs */
582 /* XXX try to share code with the counting loop! */
584 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
587 if (bptr->flags < BBFINISHED)
590 /* get info about this block */
593 iinfo = bptr->inlineinfo;
595 /* initialize javalocals at the start of this block */
597 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
599 /* create replacement points at targets of backward branches */
601 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
603 i = (iinfo) ? iinfo->throughcount : 0;
604 replace_create_replacement_point(jd, iinfo, rp++,
605 bptr->type, bptr->iinstr, &ra,
606 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
608 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
609 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
612 /* iterate over the instructions */
615 iend = iptr + bptr->icount;
617 for (; iptr != iend; ++iptr) {
619 #if defined(ENABLE_GC_CACAO)
621 md = iptr->sx.s23.s3.bte->md;
623 i = (iinfo) ? iinfo->throughcount : 0;
624 replace_create_replacement_point(jd, iinfo, rp++,
625 RPLPOINT_TYPE_CALL, iptr, &ra,
626 javalocals, iptr->sx.s23.s2.args,
627 iptr->s1.argcount - i,
632 case ICMD_INVOKESTATIC:
633 case ICMD_INVOKESPECIAL:
634 case ICMD_INVOKEVIRTUAL:
635 case ICMD_INVOKEINTERFACE:
636 INSTRUCTION_GET_METHODDESC(iptr, md);
638 i = (iinfo) ? iinfo->throughcount : 0;
639 replace_create_replacement_point(jd, iinfo, rp++,
640 RPLPOINT_TYPE_CALL, iptr, &ra,
641 javalocals, iptr->sx.s23.s2.args,
642 iptr->s1.argcount - i,
651 stack_javalocals_store(iptr, javalocals);
659 replace_create_replacement_point(jd, iinfo, rp++,
660 RPLPOINT_TYPE_RETURN, iptr, &ra,
661 NULL, &(iptr->s1.varindex), 1, 0);
665 replace_create_replacement_point(jd, iinfo, rp++,
666 RPLPOINT_TYPE_RETURN, iptr, &ra,
670 case ICMD_INLINE_START:
671 iinfo = replace_create_inline_start_replacement_point(
672 jd, rp++, iptr, &ra, javalocals);
674 /* javalocals may be set at next block start, or now */
675 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
678 case ICMD_INLINE_BODY:
679 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
681 jl = iinfo->javalocals_start;
683 /* get the javalocals from the following block start */
685 jl = bptr->next->javalocals;
687 /* create a non-trappable rplpoint */
688 replace_create_replacement_point(jd, iinfo, rp++,
689 RPLPOINT_TYPE_BODY, iptr, &ra,
691 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
694 case ICMD_INLINE_END:
695 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
696 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
697 iinfo = iptr->sx.s23.s3.inlineinfo;
699 if (iinfo->javalocals_end)
700 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
701 iinfo = iinfo->parent;
704 } /* end instruction loop */
705 } /* end basicblock loop */
707 assert((rp - rplpoints) == count);
708 assert((ra - regalloc) == alloccount);
710 /* store the data in the codeinfo */
712 code->rplpoints = rplpoints;
713 code->rplpointcount = count;
714 code->regalloc = regalloc;
715 code->regalloccount = alloccount;
716 code->globalcount = 0;
717 code->memuse = rd->memuse;
719 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
720 REPLACE_COUNT_INC(stat_regallocs, alloccount);
722 /* everything alright */
728 /* replace_free_replacement_points *********************************************
730 Free memory used by replacement points.
733 code.............codeinfo whose replacement points should be freed.
735 *******************************************************************************/
737 void replace_free_replacement_points(codeinfo *code)
742 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
745 MFREE(code->regalloc,rplalloc,code->regalloccount);
747 code->rplpoints = NULL;
748 code->rplpointcount = 0;
749 code->regalloc = NULL;
750 code->regalloccount = 0;
751 code->globalcount = 0;
755 /******************************************************************************/
756 /* PART II: Activating / deactivating replacement points */
757 /******************************************************************************/
760 /* replace_activate_replacement_points *****************************************
762 Activate the replacement points of the given compilation unit. When this
763 function returns, the replacement points are "armed", so each thread
764 reaching one of the points will enter the replacement mechanism.
767 code.............codeinfo of which replacement points should be
769 mappable.........if true, only mappable replacement points are
772 *******************************************************************************/
774 void replace_activate_replacement_points(codeinfo *code, bool mappable)
781 assert(code->savedmcode == NULL);
783 /* count trappable replacement points */
786 i = code->rplpointcount;
787 rp = code->rplpoints;
789 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
792 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
798 /* allocate buffer for saved machine code */
800 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
801 code->savedmcode = savedmcode;
802 savedmcode += count * REPLACEMENT_PATCH_SIZE;
804 /* activate trappable replacement points */
805 /* (in reverse order to handle overlapping points within basic blocks) */
807 i = code->rplpointcount;
808 rp = code->rplpoints + i;
810 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
812 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
815 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
818 DOLOG( printf("activate replacement point:\n");
819 replace_replacement_point_println(rp, 1); fflush(stdout); );
821 savedmcode -= REPLACEMENT_PATCH_SIZE;
823 #if defined(ENABLE_JIT)
824 # if defined(ENABLE_DISASSEMBLER)
825 DOLOG( printf("\tinstruction before: ");
826 disassinstr(rp->pc); fflush(stdout); );
829 md_patch_replacement_point(rp->pc, savedmcode, false);
831 # if defined(ENABLE_DISASSEMBLER)
832 DOLOG( printf("\tinstruction after : ");
833 disassinstr(rp->pc); fflush(stdout); );
837 rp->flags |= RPLPOINT_FLAG_ACTIVE;
840 assert(savedmcode == code->savedmcode);
844 /* replace_deactivate_replacement_points ***************************************
846 Deactivate a replacement points in the given compilation unit.
847 When this function returns, the replacement points will be "un-armed",
848 that is a each thread reaching a point will just continue normally.
851 code.............the compilation unit
853 *******************************************************************************/
855 void replace_deactivate_replacement_points(codeinfo *code)
862 if (code->savedmcode == NULL) {
863 /* disarm countdown points by patching the branches */
865 i = code->rplpointcount;
866 rp = code->rplpoints;
868 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
869 == RPLPOINT_FLAG_COUNTDOWN)
872 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
879 assert(code->savedmcode != NULL);
880 savedmcode = code->savedmcode;
882 /* de-activate each trappable replacement point */
884 i = code->rplpointcount;
885 rp = code->rplpoints;
888 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
893 DOLOG( printf("deactivate replacement point:\n");
894 replace_replacement_point_println(rp, 1); fflush(stdout); );
896 #if defined(ENABLE_JIT)
897 # if defined(ENABLE_DISASSEMBLER)
898 DOLOG( printf("\tinstruction before: ");
899 disassinstr(rp->pc); fflush(stdout); );
902 md_patch_replacement_point(rp->pc, savedmcode, true);
904 # if defined(ENABLE_DISASSEMBLER)
905 DOLOG( printf("\tinstruction before: ");
906 disassinstr(rp->pc); fflush(stdout); );
910 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
912 savedmcode += REPLACEMENT_PATCH_SIZE;
915 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
917 /* free saved machine code */
919 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
920 code->savedmcode = NULL;
924 /******************************************************************************/
925 /* PART III: The replacement mechanism */
926 /******************************************************************************/
929 /* replace_read_value **********************************************************
931 Read a value with the given allocation from the execution state.
934 es...............execution state
935 ra...............allocation
936 javaval..........where to put the value
939 *javaval.........the value
941 *******************************************************************************/
943 static void replace_read_value(executionstate_t *es,
945 replace_val_t *javaval)
947 if (ra->flags & INMEMORY) {
948 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
949 #ifdef HAS_4BYTE_STACKSLOT
950 if (IS_2_WORD_TYPE(ra->type)) {
951 javaval->l = *(u8*)(es->sp + ra->regoff);
955 javaval->p = *(ptrint*)(es->sp + ra->regoff);
956 #ifdef HAS_4BYTE_STACKSLOT
961 /* allocated register */
962 if (IS_FLT_DBL_TYPE(ra->type)) {
963 javaval->d = es->fltregs[ra->regoff];
965 if (ra->type == TYPE_FLT)
966 javaval->f = javaval->d;
968 #if defined(HAS_ADDRESS_REGISTER_FILE)
969 else if (IS_ADR_TYPE(ra->type)) {
970 javaval->p = es->adrregs[ra->regoff];
974 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
975 if (ra->type == TYPE_LNG) {
976 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
977 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
980 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
981 javaval->p = es->intregs[ra->regoff];
987 /* replace_write_value *********************************************************
989 Write a value to the given allocation in the execution state.
992 es...............execution state
993 ra...............allocation
994 *javaval.........the value
996 *******************************************************************************/
998 static void replace_write_value(executionstate_t *es,
1000 replace_val_t *javaval)
1002 if (ra->flags & INMEMORY) {
1003 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1004 #ifdef HAS_4BYTE_STACKSLOT
1005 if (IS_2_WORD_TYPE(ra->type)) {
1006 *(u8*)(es->sp + ra->regoff) = javaval->l;
1010 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1011 #ifdef HAS_4BYTE_STACKSLOT
1016 /* allocated register */
1019 es->fltregs[ra->regoff] = (double) javaval->f;
1022 es->fltregs[ra->regoff] = javaval->d;
1024 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1026 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1027 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1030 #if defined(HAS_ADDRESS_REGISTER_FILE)
1032 es->adrregs[ra->regoff] = javaval->p;
1035 es->intregs[ra->regoff] = javaval->p;
1041 /* replace_new_sourceframe *****************************************************
1043 Allocate a new source frame and insert it at the front of the frame list.
1046 ss...............the source state
1049 ss->frames.......set to new frame (the new head of the frame list).
1052 returns the new frame
1054 *******************************************************************************/
1056 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1058 sourceframe_t *frame;
1060 frame = (sourceframe_t*) DumpMemory::allocate(sizeof(sourceframe_t));
1061 MZERO(frame, sourceframe_t, 1);
1063 frame->down = ss->frames;
1070 /* replace_read_executionstate *************************************************
1072 Read a source frame from the given executions state.
1073 The new source frame is pushed to the front of the frame list of the
1077 rp...............replacement point at which `es` was taken
1078 es...............execution state
1079 ss...............the source state to add the source frame to
1080 topframe.........true, if the first (top-most) source frame on the
1084 *ss..............the source state with the newly created source frame
1087 *******************************************************************************/
1089 static s4 replace_normalize_type_map[] = {
1090 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1091 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1092 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1093 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1094 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1095 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1096 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1100 static void replace_read_executionstate(rplpoint *rp,
1101 executionstate_t *es,
1110 sourceframe_t *frame;
1113 stackslot_t *basesp;
1115 code = code_find_codeinfo_for_pc(rp->pc);
1117 topslot = TOP_IS_NORMAL;
1121 sp = (stackslot_t *) es->sp;
1123 /* in some cases the top stack slot is passed in REG_ITMP1 */
1125 if (rp->type == BBTYPE_EXH) {
1126 topslot = TOP_IS_IN_ITMP1;
1129 /* calculate base stack pointer */
1131 basesp = sp + code->stackframesize;
1133 /* create the source frame */
1135 frame = replace_new_sourceframe(ss);
1136 frame->method = rp->method;
1138 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1139 frame->type = replace_normalize_type_map[rp->type];
1141 frame->fromcode = code;
1143 /* read local variables */
1145 count = m->maxlocals;
1146 frame->javalocalcount = count;
1147 frame->javalocals = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1148 frame->javalocaltype = (u1*) DumpMemory::allocate(sizeof(u1) * count);
1150 /* mark values as undefined */
1151 for (i=0; i<count; ++i) {
1152 #if !defined(NDEBUG)
1153 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1155 frame->javalocaltype[i] = TYPE_VOID;
1158 /* some entries in the intregs array are not meaningful */
1159 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1160 #if !defined(NDEBUG)
1161 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1163 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1165 #endif /* !defined(NDEBUG) */
1167 /* read javalocals */
1169 count = rp->regalloccount;
1172 while (count && (i = ra->index) >= 0) {
1173 assert(i < m->maxlocals);
1174 frame->javalocaltype[i] = ra->type;
1175 if (ra->type == TYPE_RET)
1176 frame->javalocals[i].i = ra->regoff;
1178 replace_read_value(es, ra, frame->javalocals + i);
1183 /* read instance, if this is the first rplpoint */
1185 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1186 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1188 /* we are at the start of the method body, so if local 0 is set, */
1189 /* it is the instance. */
1190 if (frame->javalocaltype[0] == TYPE_ADR)
1191 frame->instance = frame->javalocals[0];
1196 md = rp->method->parseddesc;
1198 assert(md->paramcount >= 1);
1199 instra.type = TYPE_ADR;
1200 instra.regoff = md->params[0].regoff;
1201 if (md->params[0].inmemory) {
1202 instra.flags = INMEMORY;
1203 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1208 replace_read_value(es, &instra, &(frame->instance));
1211 #if defined(__I386__)
1212 else if (!(rp->method->flags & ACC_STATIC)) {
1213 /* On i386 we always pass the first argument on stack. */
1214 frame->instance.a = *(java_object_t **)(basesp + 1);
1217 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1219 /* read stack slots */
1221 frame->javastackdepth = count;
1222 frame->javastack = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1223 frame->javastacktype = (u1*) DumpMemory::allocate(sizeof(u1) * count);
1225 #if !defined(NDEBUG)
1226 /* mark values as undefined */
1227 for (i=0; i<count; ++i) {
1228 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1229 frame->javastacktype[i] = TYPE_VOID;
1231 #endif /* !defined(NDEBUG) */
1235 /* the first stack slot is special in SBR and EXH blocks */
1237 if (topslot == TOP_IS_ON_STACK) {
1240 assert(ra->index == RPLALLOC_STACK);
1241 assert(ra->type == TYPE_ADR);
1242 frame->javastack[i].p = sp[-1];
1243 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1248 else if (topslot == TOP_IS_IN_ITMP1) {
1251 assert(ra->index == RPLALLOC_STACK);
1252 assert(ra->type == TYPE_ADR);
1253 frame->javastack[i].p = es->intregs[REG_ITMP1];
1254 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1259 else if (topslot == TOP_IS_VOID) {
1262 assert(ra->index == RPLALLOC_STACK);
1263 frame->javastack[i].l = 0;
1264 frame->javastacktype[i] = TYPE_VOID;
1270 /* read remaining stack slots */
1272 for (; count--; ra++) {
1273 if (ra->index == RPLALLOC_SYNC) {
1274 assert(rp->type == RPLPOINT_TYPE_INLINE);
1276 /* only read synchronization slots when traversing an inline point */
1279 sourceframe_t *calleeframe = frame->down;
1280 assert(calleeframe);
1281 assert(calleeframe->syncslotcount == 0);
1282 assert(calleeframe->syncslots == NULL);
1284 calleeframe->syncslotcount = 1;
1285 calleeframe->syncslots = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t));
1286 replace_read_value(es,ra,calleeframe->syncslots);
1289 frame->javastackdepth--;
1293 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1295 /* do not read parameters of calls down the call chain */
1297 if (!topframe && ra->index == RPLALLOC_PARAM) {
1298 frame->javastackdepth--;
1301 if (ra->type == TYPE_RET)
1302 frame->javastack[i].i = ra->regoff;
1304 replace_read_value(es,ra,frame->javastack + i);
1305 frame->javastacktype[i] = ra->type;
1312 /* replace_write_executionstate ************************************************
1314 Pop a source frame from the front of the frame list of the given source state
1315 and write its values into the execution state.
1318 rp...............replacement point for which execution state should be
1320 es...............the execution state to modify
1321 ss...............the given source state
1322 topframe.........true, if this is the last (top-most) source frame to be
1326 *es..............the execution state derived from the source state
1328 *******************************************************************************/
1330 static void replace_write_executionstate(rplpoint *rp,
1331 executionstate_t *es,
1340 sourceframe_t *frame;
1343 stackslot_t *basesp;
1345 code = code_find_codeinfo_for_pc(rp->pc);
1347 topslot = TOP_IS_NORMAL;
1349 /* pop a source frame */
1353 ss->frames = frame->down;
1355 /* calculate stack pointer */
1357 sp = (stackslot_t *) es->sp;
1359 basesp = sp + code->stackframesize;
1361 /* in some cases the top stack slot is passed in REG_ITMP1 */
1363 if (rp->type == BBTYPE_EXH) {
1364 topslot = TOP_IS_IN_ITMP1;
1367 /* write javalocals */
1370 count = rp->regalloccount;
1372 while (count && (i = ra->index) >= 0) {
1373 assert(i < m->maxlocals);
1374 assert(i < frame->javalocalcount);
1375 assert(ra->type == frame->javalocaltype[i]);
1376 if (ra->type == TYPE_RET) {
1377 /* XXX assert that it matches this rplpoint */
1380 replace_write_value(es, ra, frame->javalocals + i);
1385 /* write stack slots */
1389 /* the first stack slot is special in SBR and EXH blocks */
1391 if (topslot == TOP_IS_ON_STACK) {
1394 assert(ra->index == RPLALLOC_STACK);
1395 assert(i < frame->javastackdepth);
1396 assert(frame->javastacktype[i] == TYPE_ADR);
1397 sp[-1] = frame->javastack[i].p;
1402 else if (topslot == TOP_IS_IN_ITMP1) {
1405 assert(ra->index == RPLALLOC_STACK);
1406 assert(i < frame->javastackdepth);
1407 assert(frame->javastacktype[i] == TYPE_ADR);
1408 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1413 else if (topslot == TOP_IS_VOID) {
1416 assert(ra->index == RPLALLOC_STACK);
1417 assert(i < frame->javastackdepth);
1418 assert(frame->javastacktype[i] == TYPE_VOID);
1424 /* write remaining stack slots */
1426 for (; count--; ra++) {
1427 if (ra->index == RPLALLOC_SYNC) {
1428 assert(rp->type == RPLPOINT_TYPE_INLINE);
1430 /* only write synchronization slots when traversing an inline point */
1433 assert(frame->down);
1434 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1435 assert(frame->down->syncslots != NULL);
1437 replace_write_value(es,ra,frame->down->syncslots);
1442 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1444 /* do not write parameters of calls down the call chain */
1446 if (!topframe && ra->index == RPLALLOC_PARAM) {
1449 ra->index = RPLALLOC_PARAM;
1452 replace_write_value(es,ra,&v);
1456 assert(i < frame->javastackdepth);
1457 assert(ra->type == frame->javastacktype[i]);
1458 if (ra->type == TYPE_RET) {
1459 /* XXX assert that it matches this rplpoint */
1462 replace_write_value(es,ra,frame->javastack + i);
1474 /* md_pop_stackframe ***********************************************************
1476 Restore callee-saved registers (including the RA register),
1477 set the stack pointer to the next stackframe,
1478 set the PC to the return address of the popped frame.
1480 *** This function imitates the effects of the method epilog ***
1481 *** and returning from the method call. ***
1484 es...............execution state
1487 *es..............the execution state after popping the stack frame
1488 NOTE: es->code and es->pv are NOT updated.
1490 *******************************************************************************/
1492 void md_pop_stackframe(executionstate_t *es)
1498 stackslot_t *basesp;
1503 /* calculate the size of the stackframe */
1505 framesize = md_stacktrace_get_framesize(es->code);
1507 /* read the return address */
1509 #if STACKFRAME_LEAFMETHODS_RA_REGISTER
1510 if (code_is_leafmethod(es->code))
1514 ra = (u1*) md_stacktrace_get_returnaddress(es->sp, framesize);
1516 /* calculate the base of the stack frame */
1518 sp = (stackslot_t *) es->sp;
1519 basesp = sp + es->code->stackframesize;
1521 /* restore return address, if part of frame */
1523 #if STACKFRAME_RA_TOP_OF_FRAME
1524 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
1525 if (!code_is_leafmethod(es->code))
1527 es->ra = (u1*) (ptrint) *--basesp;
1528 #endif /* STACKFRAME_RA_TOP_OF_FRAME */
1530 #if defined(REPLACE_RA_LINKAGE_AREA)
1531 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
1532 if (!code_is_leafmethod(es->code))
1534 es->ra = (u1*) (ptrint) basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1535 #endif /* REPLACE_RA_LINKAGE_AREA */
1537 /* restore saved int registers */
1540 for (i=0; i<es->code->savedintcount; ++i) {
1541 while (nregdescint[--reg] != REG_SAV)
1543 es->intregs[reg] = *--basesp;
1546 /* restore saved flt registers */
1550 for (i=0; i<es->code->savedfltcount; ++i) {
1551 while (nregdescfloat[--reg] != REG_SAV)
1553 basesp -= STACK_SLOTS_PER_FLOAT;
1554 es->fltregs[reg] = *(double*)basesp;
1557 #if defined(HAS_ADDRESS_REGISTER_FILE)
1558 /* restore saved adr registers */
1561 for (i=0; i<es->code->savedadrcount; ++i) {
1562 while (nregdescadr[--reg] != REG_SAV)
1564 es->adrregs[reg] = *--basesp;
1568 /* adjust the stackpointer */
1570 es->sp += framesize;
1571 #if STACKFRMAE_RA_BETWEEN_FRAMES
1572 es->sp += SIZEOF_VOID_P; /* skip return address */
1575 /* set the program counter to the return address */
1579 /* in debugging mode clobber non-saved registers */
1581 #if !defined(NDEBUG)
1583 for (i=0; i<INT_REG_CNT; ++i)
1584 if (nregdescint[i] != REG_SAV)
1585 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1586 for (i=0; i<FLT_REG_CNT; ++i)
1587 if (nregdescfloat[i] != REG_SAV)
1588 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1589 # if defined(HAS_ADDRESS_REGISTER_FILE)
1590 for (i=0; i<ADR_REG_CNT; ++i)
1591 if (nregdescadr[i] != REG_SAV)
1592 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1594 #endif /* !defined(NDEBUG) */
1598 /* md_push_stackframe **********************************************************
1600 Save the given return address, build the new stackframe,
1601 and store callee-saved registers.
1603 *** This function imitates the effects of a call and the ***
1604 *** method prolog of the callee. ***
1607 es...............execution state
1608 calleecode.......the code we are "calling"
1609 ra...............the return address to save
1612 *es..............the execution state after pushing the stack frame
1613 NOTE: es->pc, es->code, and es->pv are NOT updated.
1615 *******************************************************************************/
1617 void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra)
1621 stackslot_t *basesp;
1627 /* write the return address */
1629 #if STACKFRMAE_RA_BETWEEN_FRAMES
1630 es->sp -= SIZEOF_VOID_P;
1631 *((void **)es->sp) = (void *) ra;
1632 if (calleecode->stackframesize)
1633 es->sp -= (SIZE_OF_STACKSLOT - SIZEOF_VOID_P);
1634 #endif /* STACKFRAME_RA_BETWEEN_FRAMES */
1636 es->ra = (u1*) (ptrint) ra;
1638 /* build the stackframe */
1640 DOLOG( printf("building stackframe of %d words at %p\n",
1641 calleecode->stackframesize, (void*)es->sp); );
1643 sp = (stackslot_t *) es->sp;
1646 sp -= calleecode->stackframesize;
1649 /* in debug mode, invalidate stack frame first */
1651 /* XXX may not invalidate linkage area used by native code! */
1653 #if !defined(NDEBUG) && 0
1654 for (i=0; i< (basesp - sp) && i < 1; ++i) {
1655 sp[i] = 0xdeaddeadU;
1659 #if defined(__I386__)
1660 /* Stackslot 0 may contain the object instance for vftbl patching.
1661 Destroy it, so there's no undefined value used. */
1662 if ((basesp - sp) > 0) {
1667 /* save the return address register */
1669 #if STACKFRAME_RA_TOP_OF_FRAME
1670 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
1671 if (!code_is_leafmethod(calleecode))
1673 *--basesp = (ptrint) ra;
1674 #endif /* STACKFRAME_RA_TOP_OF_FRAME */
1676 #if defined(REPLACE_RA_LINKAGE_AREA)
1677 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
1678 if (!code_is_leafmethod(calleecode))
1680 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1681 #endif /* REPLACE_RA_LINKAGE_AREA */
1683 /* save int registers */
1686 for (i=0; i<calleecode->savedintcount; ++i) {
1687 while (nregdescint[--reg] != REG_SAV)
1689 *--basesp = es->intregs[reg];
1691 /* XXX may not clobber saved regs used by native code! */
1692 #if !defined(NDEBUG) && 0
1693 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1697 /* save flt registers */
1701 for (i=0; i<calleecode->savedfltcount; ++i) {
1702 while (nregdescfloat[--reg] != REG_SAV)
1704 basesp -= STACK_SLOTS_PER_FLOAT;
1705 *(double*)basesp = es->fltregs[reg];
1707 /* XXX may not clobber saved regs used by native code! */
1708 #if !defined(NDEBUG) && 0
1709 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1713 #if defined(HAS_ADDRESS_REGISTER_FILE)
1714 /* save adr registers */
1717 for (i=0; i<calleecode->savedadrcount; ++i) {
1718 while (nregdescadr[--reg] != REG_SAV)
1720 *--basesp = es->adrregs[reg];
1722 /* XXX may not clobber saved regs used by native code! */
1723 #if !defined(NDEBUG) && 0
1724 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1731 /* replace_pop_activation_record ***********************************************
1733 Peel a stack frame from the execution state.
1735 *** This function imitates the effects of the method epilog ***
1736 *** and returning from the method call. ***
1739 es...............execution state
1740 frame............source frame, receives synchronization slots
1743 *es..............the execution state after popping the stack frame
1746 the return address of the poped activation record
1748 *******************************************************************************/
1750 u1* replace_pop_activation_record(executionstate_t *es,
1751 sourceframe_t *frame)
1762 /* calculate the base of the stack frame */
1764 sp = (stackslot_t *) es->sp;
1765 assert(frame->syncslotcount == 0);
1766 assert(frame->syncslots == NULL);
1767 count = code_get_sync_slot_count(es->code);
1768 frame->syncslotcount = count;
1769 frame->syncslots = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1770 for (i=0; i<count; ++i) {
1771 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX md_ function */
1774 /* pop the stackframe */
1776 md_pop_stackframe(es);
1780 DOLOG( printf("RA = %p\n", (void*)ra); );
1782 /* Subtract one from the PC so we do not hit the replacement point */
1783 /* of the instruction following the call, if there is one. */
1787 /* find the new codeinfo */
1789 void* pv = md_codegen_get_pv_from_pc(ra);
1790 DOLOG( printf("PV = %p\n", pv); );
1792 code = code_get_codeinfo_for_pv(pv);
1793 DOLOG( printf("CODE = %p\n", (void*) code); );
1795 /* return NULL if we reached native code */
1797 es->pv = (uint8_t*) pv;
1800 return (code) ? ra : NULL;
1804 /* replace_patch_method_pointer ************************************************
1806 Patch a method pointer (may be in code, data segment, vftbl, or interface
1810 mpp..............address of the method pointer to patch
1811 entrypoint.......the new entrypoint of the method
1812 kind.............kind of call to patch, used only for debugging
1814 *******************************************************************************/
1816 static void replace_patch_method_pointer(methodptr *mpp,
1817 methodptr entrypoint,
1820 #if !defined(NDEBUG)
1825 DOLOG( printf("patch method pointer from: %p to %p\n",
1826 (void*) *mpp, (void*)entrypoint); );
1828 #if !defined(NDEBUG)
1829 oldcode = code_get_codeinfo_for_pv(*mpp);
1830 newcode = code_get_codeinfo_for_pv(entrypoint);
1832 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1833 method_println(oldcode->m);
1834 printf("\t with %p ", (void*) newcode);
1835 method_println(newcode->m); );
1837 assert(oldcode->m == newcode->m);
1840 /* write the new entrypoint */
1842 *mpp = (methodptr) entrypoint;
1846 /* replace_patch_class *********************************************************
1848 Patch a method in the given class.
1851 vftbl............vftbl of the class
1852 m................the method to patch
1853 oldentrypoint....the old entrypoint to replace
1854 entrypoint.......the new entrypoint
1856 *******************************************************************************/
1858 void replace_patch_class(vftbl_t *vftbl,
1867 /* patch the vftbl of the class */
1869 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1873 /* patch the interface tables */
1875 assert(oldentrypoint);
1877 for (i=0; i < vftbl->interfacetablelength; ++i) {
1878 mpp = vftbl->interfacetable[-i];
1879 mppend = mpp + vftbl->interfacevftbllength[i];
1880 for (; mpp != mppend; ++mpp)
1881 if (*mpp == oldentrypoint) {
1882 replace_patch_method_pointer(mpp, entrypoint, "interface");
1888 /* replace_patch_class_hierarchy ***********************************************
1890 Patch a method in all loaded classes.
1893 m................the method to patch
1894 oldentrypoint....the old entrypoint to replace
1895 entrypoint.......the new entrypoint
1897 *******************************************************************************/
1899 struct replace_patch_data_t {
1905 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1907 vftbl_t *vftbl = c->vftbl;
1910 && vftbl->vftbllength > pd->m->vftblindex
1911 && (void*) vftbl->table[pd->m->vftblindex] != (void*) (uintptr_t) &asm_abstractmethoderror
1912 && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
1914 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1918 void replace_patch_class_hierarchy(methodinfo *m,
1922 struct replace_patch_data_t pd;
1925 pd.oldentrypoint = oldentrypoint;
1926 pd.entrypoint = entrypoint;
1928 DOLOG_SHORT( printf("patching class hierarchy: ");
1929 method_println(m); );
1931 classcache_foreach_loaded_class(
1932 (classcache_foreach_functionptr_t) &replace_patch_callback,
1937 /* replace_patch_future_calls **************************************************
1939 Analyse a call site and depending on the kind of call patch the call, the
1940 virtual function table, or the interface table.
1943 ra...............return address pointing after the call site
1944 callerframe......source frame of the caller
1945 calleeframe......source frame of the callee, must have been mapped
1947 *******************************************************************************/
1949 void replace_patch_future_calls(u1 *ra,
1950 sourceframe_t *callerframe,
1951 sourceframe_t *calleeframe)
1954 methodptr entrypoint;
1955 methodptr oldentrypoint;
1958 codeinfo *calleecode;
1959 methodinfo *calleem;
1964 assert(callerframe->down == calleeframe);
1966 /* get the new codeinfo and the method that shall be entered */
1968 calleecode = calleeframe->tocode;
1971 calleem = calleeframe->method;
1972 assert(calleem == calleecode->m);
1974 entrypoint = (methodptr) calleecode->entrypoint;
1976 /* check if we are at an method entry rplpoint at the innermost frame */
1978 atentry = (calleeframe->down == NULL)
1979 && !(calleem->flags & ACC_STATIC)
1980 && (calleeframe->fromrp->id == 0); /* XXX */
1982 /* get the position to patch, in case it was a statically bound call */
1984 pv = callerframe->fromcode->entrypoint;
1985 patchpos = (u1*) md_jit_method_patch_address(pv, ra, NULL);
1987 if (patchpos == NULL) {
1988 /* the call was dispatched dynamically */
1990 /* we can only patch such calls if we are at the entry point */
1992 #if !defined(__I386__)
1993 /* On i386 we always know the instance argument. */
1998 assert((calleem->flags & ACC_STATIC) == 0);
2000 oldentrypoint = calleeframe->fromcode->entrypoint;
2002 /* we need to know the instance */
2004 if (!calleeframe->instance.a) {
2005 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
2006 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
2012 obj = calleeframe->instance.a;
2015 assert(vftbl->clazz->vftbl == vftbl);
2017 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->clazz); );
2019 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
2022 /* the call was statically bound */
2024 #if defined(__I386__)
2025 /* It happens that there is a patcher trap. (pm) */
2026 if (*(u2 *)(patchpos - 1) == 0x0b0f) {
2029 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
2034 /* replace_push_activation_record **********************************************
2036 Push a stack frame onto the execution state.
2038 *** This function imitates the effects of a call and the ***
2039 *** method prolog of the callee. ***
2042 es...............execution state
2043 rpcall...........the replacement point at the call site
2044 callerframe......source frame of the caller, or NULL for creating the
2046 calleeframe......source frame of the callee, must have been mapped
2049 *es..............the execution state after pushing the stack frame
2051 *******************************************************************************/
2053 void replace_push_activation_record(executionstate_t *es,
2055 sourceframe_t *callerframe,
2056 sourceframe_t *calleeframe)
2062 codeinfo *calleecode;
2065 assert(!rpcall || callerframe);
2066 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
2067 assert(!rpcall || rpcall == callerframe->torp);
2068 assert(calleeframe);
2069 assert(!callerframe || calleeframe == callerframe->down);
2071 /* the compilation unit we are entering */
2073 calleecode = calleeframe->tocode;
2076 /* calculate the return address */
2079 ra = rpcall->pc + rpcall->callsize;
2081 ra = es->pc + 1 /* XXX this is ugly */;
2083 /* push the stackframe */
2085 md_push_stackframe(es, calleecode, ra);
2087 /* we move into a new code unit, set code, PC, PV */
2089 es->code = calleecode;
2090 es->pc = calleecode->entrypoint; /* XXX not needed? */
2091 es->pv = calleecode->entrypoint;
2093 /* write slots used for synchronization */
2095 sp = (stackslot_t *) es->sp;
2096 count = code_get_sync_slot_count(calleecode);
2097 assert(count == calleeframe->syncslotcount);
2098 for (i=0; i<count; ++i) {
2099 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2102 /* redirect future invocations */
2104 if (callerframe && rpcall) {
2105 #if defined(REPLACE_PATCH_ALL)
2106 if (rpcall->type == callerframe->fromrp->type)
2108 if (rpcall == callerframe->fromrp)
2110 replace_patch_future_calls(ra, callerframe, calleeframe);
2115 /* replace_find_replacement_point **********************************************
2117 Find the replacement point in the given code corresponding to the
2118 position given in the source frame.
2121 code.............the codeinfo in which to search the rplpoint
2122 frame............the source frame defining the position to look for
2123 parent...........parent replacement point to match
2126 the replacement point
2128 *******************************************************************************/
2130 rplpoint * replace_find_replacement_point(codeinfo *code,
2131 sourceframe_t *frame,
2144 DOLOG( printf("searching replacement point for:\n");
2145 replace_source_frame_println(frame); );
2149 DOLOG( printf("code = %p\n", (void*)code); );
2151 rp = code->rplpoints;
2152 i = code->rplpointcount;
2154 if (rp->id == frame->id && rp->method == frame->method
2155 && rp->parent == parent
2156 && replace_normalize_type_map[rp->type] == frame->type)
2158 /* check if returnAddresses match */
2159 /* XXX optimize: only do this if JSRs in method */
2160 DOLOG( printf("checking match for:");
2161 replace_replacement_point_println(rp, 1); fflush(stdout); );
2164 for (j = rp->regalloccount; j--; ++ra) {
2165 if (ra->type == TYPE_RET) {
2166 if (ra->index == RPLALLOC_STACK) {
2167 assert(stacki < frame->javastackdepth);
2168 if (frame->javastack[stacki].i != ra->regoff)
2173 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2174 if (frame->javalocals[ra->index].i != ra->regoff)
2187 #if !defined(NDEBUG)
2188 printf("candidate replacement points were:\n");
2189 rp = code->rplpoints;
2190 i = code->rplpointcount;
2192 replace_replacement_point_println(rp, 1);
2196 vm_abort("no matching replacement point found");
2197 return NULL; /* NOT REACHED */
2201 /* replace_find_replacement_point_for_pc ***************************************
2203 Find the nearest replacement point at or before the given PC. The
2204 given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
2205 the replacement point to be found.
2208 code.............compilation unit the PC is in
2209 pc...............the machine code PC
2212 the replacement point found, or
2213 NULL if no replacement point was found
2215 *******************************************************************************/
2217 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc, unsigned desired_flags)
2223 DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
2224 method_println(code->m); );
2228 rp = code->rplpoints;
2229 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2230 DOLOG( replace_replacement_point_println(rp, 2); );
2231 if (rp->pc <= pc && rp->pc + rp->callsize >= pc) {
2232 if (desired_flags) {
2233 if (rp->flags & desired_flags) {
2245 /* replace_pop_native_frame ****************************************************
2247 Unroll a native frame in the execution state and create a source frame
2251 es...............current execution state
2252 ss...............the current source state
2253 sfi..............stackframeinfo for the native frame
2256 es...............execution state after unrolling the native frame
2257 ss...............gets the added native source frame
2259 *******************************************************************************/
2261 static void replace_pop_native_frame(executionstate_t *es,
2263 stackframeinfo_t *sfi)
2265 sourceframe_t *frame;
2271 frame = replace_new_sourceframe(ss);
2275 /* remember pc and size of native frame */
2277 frame->nativepc = es->pc;
2278 frame->nativeframesize = (es->sp != 0) ? (((uintptr_t) sfi->sp) - ((uintptr_t) es->sp)) : 0;
2279 assert(frame->nativeframesize >= 0);
2281 /* remember values of saved registers */
2284 for (i=0; i<INT_REG_CNT; ++i) {
2285 if (nregdescint[i] == REG_SAV)
2286 frame->nativesavint[j++] = es->intregs[i];
2290 for (i=0; i<FLT_REG_CNT; ++i) {
2291 if (nregdescfloat[i] == REG_SAV)
2292 frame->nativesavflt[j++] = es->fltregs[i];
2295 #if defined(HAS_ADDRESS_REGISTER_FILE)
2297 for (i=0; i<ADR_REG_CNT; ++i) {
2298 if (nregdescadr[i] == REG_SAV)
2299 frame->nativesavadr[j++] = es->adrregs[i];
2303 /* restore saved registers */
2305 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2307 for (i=0; i<INT_REG_CNT; ++i) {
2308 if (nregdescint[i] == REG_SAV)
2309 es->intregs[i] = sfi->intregs[j++];
2312 /* XXX we don't have them, yet, in the sfi, so clear them */
2314 for (i=0; i<INT_REG_CNT; ++i) {
2315 if (nregdescint[i] == REG_SAV)
2320 /* XXX we don't have float registers in the sfi, so clear them */
2322 for (i=0; i<FLT_REG_CNT; ++i) {
2323 if (nregdescfloat[i] == REG_SAV)
2324 es->fltregs[i] = 0.0;
2327 #if defined(HAS_ADDRESS_REGISTER_FILE)
2328 # if defined(ENABLE_GC_CACAO)
2330 for (i=0; i<ADR_REG_CNT; ++i) {
2331 if (nregdescadr[i] == REG_SAV)
2332 es->adrregs[i] = sfi->adrregs[j++];
2335 for (i=0; i<ADR_REG_CNT; ++i) {
2336 if (nregdescadr[i] == REG_SAV)
2342 /* restore codeinfo of the native stub */
2344 code = code_get_codeinfo_for_pv(sfi->pv);
2346 /* restore sp, pv, pc and codeinfo of the parent method */
2348 es->sp = (uint8_t*) (((uintptr_t) sfi->sp) + md_stacktrace_get_framesize(code));
2349 #if STACKFRMAE_RA_BETWEEN_FRAMES
2350 es->sp += SIZEOF_VOID_P; /* skip return address */
2352 es->pv = (uint8_t*) md_codegen_get_pv_from_pc(sfi->ra);
2353 es->pc = (uint8_t*) (((uintptr_t) ((sfi->xpc) ? sfi->xpc : sfi->ra)) - 1);
2354 es->code = code_get_codeinfo_for_pv(es->pv);
2358 /* replace_push_native_frame ***************************************************
2360 Rebuild a native frame onto the execution state and remove its source frame.
2362 Note: The native frame is "rebuild" by setting fields like PC and stack
2363 pointer in the execution state accordingly. Values in the
2364 stackframeinfo may be modified, but the actual stack frame of the
2365 native code is not touched.
2368 es...............current execution state
2369 ss...............the current source state
2372 es...............execution state after re-rolling the native frame
2373 ss...............the native source frame is removed
2375 *******************************************************************************/
2377 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2379 sourceframe_t *frame;
2385 DOLOG( printf("pushing native frame\n"); );
2387 /* remove the frame from the source state */
2391 assert(REPLACE_IS_NATIVE_FRAME(frame));
2393 ss->frames = frame->down;
2395 /* skip sp for the native stub */
2397 es->sp -= md_stacktrace_get_framesize(frame->sfi->code);
2398 #if STACKFRMAE_RA_BETWEEN_FRAMES
2399 es->sp -= SIZEOF_VOID_P; /* skip return address */
2402 /* assert that the native frame has not moved */
2404 assert(es->sp == frame->sfi->sp);
2406 /* update saved registers in the stackframeinfo */
2408 #if defined(ENABLE_GC_CACAO)
2410 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2411 for (i=0; i<INT_REG_CNT; ++i) {
2412 if (nregdescint[i] == REG_SAV)
2413 frame->sfi->intregs[j++] = es->intregs[i];
2416 for (i=0; i<ADR_REG_CNT; ++i) {
2417 if (nregdescadr[i] == REG_SAV)
2418 frame->sfi->adrregs[j++] = es->adrregs[i];
2422 /* XXX leave float registers untouched here */
2425 /* restore saved registers */
2428 for (i=0; i<INT_REG_CNT; ++i) {
2429 if (nregdescint[i] == REG_SAV)
2430 es->intregs[i] = frame->nativesavint[j++];
2434 for (i=0; i<FLT_REG_CNT; ++i) {
2435 if (nregdescfloat[i] == REG_SAV)
2436 es->fltregs[i] = frame->nativesavflt[j++];
2439 #if defined(HAS_ADDRESS_REGISTER_FILE)
2441 for (i=0; i<ADR_REG_CNT; ++i) {
2442 if (nregdescadr[i] == REG_SAV)
2443 es->adrregs[i] = frame->nativesavadr[j++];
2447 /* skip the native frame on the machine stack */
2449 es->sp -= frame->nativeframesize;
2451 /* set the pc the next frame must return to */
2453 es->pc = frame->nativepc;
2457 /* replace_recover_source_state ************************************************
2459 Recover the source state from the given replacement point and execution
2463 rp...............replacement point that has been reached, if any
2464 sfi..............stackframeinfo, if called from native code
2465 es...............execution state at the replacement point rp
2470 *******************************************************************************/
2472 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2473 stackframeinfo_t *sfi,
2474 executionstate_t *es)
2479 #if defined(REPLACE_STATISTICS)
2483 /* create the source frame structure in dump memory */
2485 ss = (sourcestate_t*) DumpMemory::allocate(sizeof(sourcestate_t));
2488 /* each iteration of the loop recovers one source frame */
2495 DOLOG( executionstate_println(es); );
2497 /* if we are not at a replacement point, it is a native frame */
2500 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2503 replace_pop_native_frame(es, ss, sfi);
2506 if (es->code == NULL)
2509 goto after_machine_frame;
2512 /* read the values for this source frame from the execution state */
2514 DOLOG( printf("recovering source state for%s:\n",
2515 (ss->frames == NULL) ? " TOPFRAME" : "");
2516 replace_replacement_point_println(rp, 1); );
2518 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2520 #if defined(ENABLE_VMLOG)
2521 vmlog_cacao_unrol_method(ss->frames->method);
2524 #if defined(REPLACE_STATISTICS)
2525 REPLACE_COUNT(stat_frames);
2527 replace_statistics_source_frame(ss->frames);
2530 /* in locked areas (below native frames), identity map the frame */
2533 ss->frames->torp = ss->frames->fromrp;
2534 ss->frames->tocode = ss->frames->fromcode;
2537 /* unroll to the next (outer) frame */
2540 /* this frame is in inlined code */
2542 DOLOG( printf("INLINED!\n"); );
2546 assert(rp->type == RPLPOINT_TYPE_INLINE);
2547 REPLACE_COUNT(stat_unroll_inline);
2550 /* this frame had been called at machine-level. pop it. */
2552 DOLOG( printf("UNWIND\n"); );
2554 ra = replace_pop_activation_record(es, ss->frames);
2556 DOLOG( printf("REACHED NATIVE CODE\n"); );
2560 #if !defined(ENABLE_GC_CACAO)
2561 break; /* XXX remove to activate native frames */
2566 /* find the replacement point at the call site */
2568 after_machine_frame:
2569 rp = replace_find_replacement_point_for_pc(es->code, es->pc, 0);
2572 vm_abort("could not find replacement point while unrolling call");
2574 DOLOG( printf("found replacement point.\n");
2575 replace_replacement_point_println(rp, 1); );
2577 assert(rp->type == RPLPOINT_TYPE_CALL);
2578 REPLACE_COUNT(stat_unroll_call);
2580 } /* end loop over source frames */
2582 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2588 /* replace_map_source_state ****************************************************
2590 Map each source frame in the given source state to a target replacement
2591 point and compilation unit. If no valid code is available for a source
2592 frame, it is (re)compiled.
2595 ss...............the source state
2598 ss...............the source state, modified: The `torp` and `tocode`
2599 fields of each source frame are set.
2602 true.............everything went ok
2603 false............an exception has been thrown
2605 *******************************************************************************/
2607 static bool replace_map_source_state(sourcestate_t *ss)
2609 sourceframe_t *frame;
2612 rplpoint *parent; /* parent of inlined rplpoint */
2613 #if defined(REPLACE_STATISTICS)
2620 /* iterate over the source frames from outermost to innermost */
2622 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2624 /* XXX skip native frames */
2626 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2631 /* map frames which are not already mapped */
2633 if (frame->tocode) {
2634 code = frame->tocode;
2639 assert(frame->torp == NULL);
2641 if (parent == NULL) {
2642 /* find code for this frame */
2644 #if defined(REPLACE_STATISTICS)
2645 oldcode = frame->method->code;
2647 /* request optimization of hot methods and their callers */
2649 if (frame->method->hitcountdown < 0
2650 || (frame->down && frame->down->method->hitcountdown < 0))
2651 jit_request_optimization(frame->method);
2653 code = jit_get_current_code(frame->method);
2656 return false; /* exception */
2658 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2663 /* map this frame */
2665 rp = replace_find_replacement_point(code, frame, parent);
2667 frame->tocode = code;
2671 if (rp->type == RPLPOINT_TYPE_CALL) {
2684 /* replace_map_source_state_identity *******************************************
2686 Map each source frame in the given source state to the same replacement
2687 point and compilation unit it was derived from. This is mainly used for
2691 ss...............the source state
2694 ss...............the source state, modified: The `torp` and `tocode`
2695 fields of each source frame are set.
2697 *******************************************************************************/
2699 #if defined(ENABLE_GC_CACAO)
2700 static void replace_map_source_state_identity(sourcestate_t *ss)
2702 sourceframe_t *frame;
2704 /* iterate over the source frames from outermost to innermost */
2706 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2708 /* skip native frames */
2710 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2714 /* map frames using the identity mapping */
2716 if (frame->tocode) {
2717 assert(frame->tocode == frame->fromcode);
2718 assert(frame->torp == frame->fromrp);
2720 assert(frame->tocode == NULL);
2721 assert(frame->torp == NULL);
2722 frame->tocode = frame->fromcode;
2723 frame->torp = frame->fromrp;
2730 /* replace_build_execution_state ***********************************************
2732 Build an execution state for the given (mapped) source state.
2734 !!! CAUTION: This function rewrites the machine stack !!!
2736 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2739 ss...............the source state. Must have been mapped by
2740 replace_map_source_state before.
2741 es...............the base execution state on which to build
2744 *es..............the new execution state
2746 *******************************************************************************/
2748 static void replace_build_execution_state(sourcestate_t *ss,
2749 executionstate_t *es)
2752 sourceframe_t *prevframe;
2759 while (ss->frames) {
2761 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2762 prevframe = ss->frames;
2763 replace_push_native_frame(es, ss);
2769 if (parent == NULL) {
2770 /* create a machine-level stack frame */
2772 DOLOG( printf("pushing activation record for:\n");
2773 if (rp) replace_replacement_point_println(rp, 1);
2774 else printf("\tfirst frame\n"); );
2776 replace_push_activation_record(es, rp, prevframe, ss->frames);
2778 DOLOG( executionstate_println(es); );
2781 rp = ss->frames->torp;
2784 DOLOG( printf("creating execution state for%s:\n",
2785 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2786 replace_replacement_point_println(ss->frames->fromrp, 1);
2787 replace_replacement_point_println(rp, 1); );
2789 es->code = ss->frames->tocode;
2790 prevframe = ss->frames;
2792 #if defined(ENABLE_VMLOG)
2793 vmlog_cacao_rerol_method(ss->frames->method);
2796 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2798 DOLOG( executionstate_println(es); );
2800 if (rp->type == RPLPOINT_TYPE_CALL) {
2811 /* replace_me ******************************************************************
2813 This function is called by the signal handler when a thread reaches
2814 a replacement point. `replace_me` must map the execution state to the
2815 target replacement point and let execution continue there.
2817 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2820 rp...............replacement point that has been reached
2821 es...............execution state read by signal handler
2823 *******************************************************************************/
2825 static void replace_me(rplpoint *rp, executionstate_t *es)
2827 stackframeinfo_t *sfi;
2829 sourceframe_t *frame;
2832 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2833 threadobject *thread;
2836 origcode = es->code;
2839 #if defined(ENABLE_TLH)
2840 /*printf("Replacing in %s/%s\n", rp->method->clazz->name->text, rp->method->name->text);*/
2843 /*if (strcmp(rp->method->clazz->name->text, "antlr/AlternativeElement") == 0 && strcmp(rp->method->name->text, "getAutoGenType") ==0) opt_TraceReplacement = 2; else opt_TraceReplacement = 0;*/
2845 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2846 stat_replacements, (void*)THREADOBJECT,
2848 method_println(es->code->m); );
2850 DOLOG( replace_replacement_point_println(rp, 1); );
2852 REPLACE_COUNT(stat_replacements);
2854 // Create new dump memory area.
2857 /* Get the stackframeinfo for the current thread. */
2859 sfi = threads_get_current_stackframeinfo();
2861 /* recover source state */
2863 ss = replace_recover_source_state(rp, sfi, es);
2865 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2866 /* if there is a collection pending, we assume the replacement point should
2867 suspend this thread */
2871 thread = THREADOBJECT;
2873 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2875 /* map the sourcestate using the identity mapping */
2876 replace_map_source_state_identity(ss);
2878 /* since we enter the same method again, we turn off rps now */
2879 /* XXX michi: can we really do this? what if the rp was active before
2880 we activated it for the gc? */
2881 replace_deactivate_replacement_points(origcode);
2883 /* remember executionstate and sourcestate for this thread */
2884 GC_EXECUTIONSTATE = es;
2885 GC_SOURCESTATE = ss;
2887 /* really suspend this thread now (PC = 0) */
2888 threads_suspend_ack(NULL, NULL);
2890 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2893 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2895 /* map the source state */
2897 if (!replace_map_source_state(ss))
2898 vm_abort("exception during method replacement");
2900 DOLOG( replace_sourcestate_println(ss); );
2902 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2904 #if !defined(NDEBUG)
2905 /* avoid infinite loops by self-replacement, only if not in testing mode */
2907 if (!opt_TestReplacement) {
2910 frame = frame->down;
2912 if (frame->torp == origrp) {
2914 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2916 replace_deactivate_replacement_points(origcode);
2921 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2925 /* build the new execution state */
2927 replace_build_execution_state(ss, es);
2929 #if !defined(NDEBUG)
2930 /* continue execution after patched machine code, if testing mode enabled */
2932 if (opt_TestReplacement)
2933 es->pc += REPLACEMENT_PATCH_SIZE;
2938 /* replace_me_wrapper **********************************************************
2940 This function is called by the signal handler. It determines if there
2941 is an active replacement point pending at the given PC and returns
2944 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2947 pc...............the program counter that triggered the replacement.
2948 context..........the context (machine state) to which the
2949 replacement should be applied.
2952 context..........the context after replacement finished.
2955 true.............replacement done, everything went ok
2956 false............no replacement done, context unchanged
2958 *******************************************************************************/
2960 bool replace_me_wrapper(u1 *pc, void *context)
2964 executionstate_t es;
2965 #if defined(ENABLE_RT_TIMING)
2966 struct timespec time_start, time_end;
2969 /* search the codeinfo for the given PC */
2971 code = code_find_codeinfo_for_pc(pc);
2974 /* search for a replacement point at the given PC */
2976 rp = replace_find_replacement_point_for_pc(code, pc, (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN));
2978 /* check if the replacement point belongs to given PC and is active */
2980 if ((rp != NULL) && (rp->pc == pc)
2981 && (rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))) {
2983 DOLOG( printf("valid replacement point\n"); );
2985 #if !defined(NDEBUG)
2986 executionstate_sanity_check(context);
2989 /* set codeinfo pointer in execution state */
2993 /* read execution state from current context */
2995 md_executionstate_read(&es, context);
2997 DOLOG( printf("REPLACEMENT READ: ");
2998 executionstate_println(&es); );
3000 /* do the actual replacement */
3002 #if defined(ENABLE_RT_TIMING)
3003 RT_TIMING_GET_TIME(time_start);
3006 replace_me(rp, &es);
3008 #if defined(ENABLE_RT_TIMING)
3009 RT_TIMING_GET_TIME(time_end);
3010 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_REPLACE);
3013 /* write execution state to current context */
3015 md_executionstate_write(&es, context);
3017 DOLOG( printf("REPLACEMENT WRITE: ");
3018 executionstate_println(&es); );
3020 /* new code is entered after returning */
3022 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
3030 /******************************************************************************/
3031 /* NOTE: Stuff specific to the exact GC is below. */
3032 /******************************************************************************/
3034 #if defined(ENABLE_GC_CACAO)
3035 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
3037 stackframeinfo_t *sfi;
3038 executionstate_t *es;
3041 /* Get the stackframeinfo of this thread. */
3043 assert(thread == THREADOBJECT);
3045 sfi = threads_get_current_stackframeinfo();
3047 /* create the execution state */
3048 es = (executionstate_t*) DumpMemory::allocate(sizeof(executionstate_t));
3051 es->pv = 0; /* since we are in a native, PV is invalid! */
3052 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
3054 /* we assume we are in a native (no replacement point)! */
3055 ss = replace_recover_source_state(NULL, sfi, es);
3057 /* map the sourcestate using the identity mapping */
3058 replace_map_source_state_identity(ss);
3060 /* remember executionstate and sourcestate for this thread */
3061 GC_EXECUTIONSTATE = es;
3062 GC_SOURCESTATE = ss;
3066 #if defined(ENABLE_GC_CACAO)
3067 void replace_gc_into_native(threadobject *thread)
3069 executionstate_t *es;
3072 /* get the executionstate and sourcestate for the given thread */
3073 es = GC_EXECUTIONSTATE;
3074 ss = GC_SOURCESTATE;
3076 /* rebuild the stack of the given thread */
3077 replace_build_execution_state(ss, es);
3082 /******************************************************************************/
3083 /* NOTE: No important code below. */
3084 /******************************************************************************/
3087 /* statistics *****************************************************************/
3089 #if defined(REPLACE_STATISTICS)
3090 static void print_freq(FILE *file,int *array,int limit)
3095 for (i=0; i<limit; ++i)
3097 sum += array[limit];
3098 for (i=0; i<limit; ++i) {
3100 fprintf(file," %3d: %8d (cum %3d%%)\n",
3101 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3103 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3105 #endif /* defined(REPLACE_STATISTICS) */
3108 #if defined(REPLACE_STATISTICS)
3110 #define REPLACE_PRINT_DIST(name, array) \
3111 printf(" " name " distribution:\n"); \
3112 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3114 void replace_print_statistics(void)
3116 printf("replacement statistics:\n");
3117 printf(" # of replacements: %d\n", stat_replacements);
3118 printf(" # of frames: %d\n", stat_frames);
3119 printf(" # of recompilations: %d\n", stat_recompile);
3120 printf(" patched static calls:%d\n", stat_staticpatch);
3121 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3122 printf(" unrolled calls: %d\n", stat_unroll_call);
3123 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3124 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3125 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3126 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3127 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3128 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3129 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3130 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3131 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3132 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3134 printf(" # of methods: %d\n", stat_methods);
3135 printf(" # of replacement points: %d\n", stat_rploints);
3136 printf(" # of regallocs: %d\n", stat_regallocs);
3137 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3138 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3139 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3143 #endif /* defined(REPLACE_STATISTICS) */
3146 #if defined(REPLACE_STATISTICS)
3147 static void replace_statistics_source_frame(sourceframe_t *frame)
3156 for (i=0; i<frame->javalocalcount; ++i) {
3157 switch (frame->javalocaltype[i]) {
3158 case TYPE_ADR: adr++; break;
3159 case TYPE_RET: ret++; break;
3160 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3161 case TYPE_VOID: vd++; break;
3166 REPLACE_COUNT_DIST(stat_dist_locals, n);
3167 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3168 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3169 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3170 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3171 adr = ret = prim = n = 0;
3172 for (i=0; i<frame->javastackdepth; ++i) {
3173 switch (frame->javastacktype[i]) {
3174 case TYPE_ADR: adr++; break;
3175 case TYPE_RET: ret++; break;
3176 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3180 REPLACE_COUNT_DIST(stat_dist_stack, n);
3181 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3182 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3183 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3185 #endif /* defined(REPLACE_STATISTICS) */
3188 /* debugging helpers **********************************************************/
3190 /* replace_replacement_point_println *******************************************
3192 Print replacement point info.
3195 rp...............the replacement point to print
3197 *******************************************************************************/
3199 #if !defined(NDEBUG)
3201 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3203 static const char *replace_type_str[] = {
3213 void replace_replacement_point_println(rplpoint *rp, int depth)
3219 printf("(rplpoint *)NULL\n");
3223 for (j=0; j<depth; ++j)
3226 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3227 rp->id, (void*)rp,rp->pc,rp->callsize,
3228 replace_type_str[rp->type]);
3229 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3231 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3232 printf(" COUNTDOWN");
3233 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3235 printf(" parent:%p\n", (void*)rp->parent);
3236 for (j=0; j<depth; ++j)
3238 printf("ra:%d = [", rp->regalloccount);
3240 for (j=0; j<rp->regalloccount; ++j) {
3243 index = rp->regalloc[j].index;
3245 case RPLALLOC_STACK: printf("S"); break;
3246 case RPLALLOC_PARAM: printf("P"); break;
3247 case RPLALLOC_SYNC : printf("Y"); break;
3248 default: printf("%d", index);
3250 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3251 if (rp->regalloc[j].type == TYPE_RET) {
3252 printf("ret(L%03d)", rp->regalloc[j].regoff);
3255 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3260 for (j=0; j<depth; ++j)
3263 method_print(rp->method);
3267 #endif /* !defined(NDEBUG) */
3270 /* replace_show_replacement_points *********************************************
3272 Print replacement point info.
3275 code.............codeinfo whose replacement points should be printed.
3277 *******************************************************************************/
3279 #if !defined(NDEBUG)
3280 void replace_show_replacement_points(codeinfo *code)
3288 printf("(codeinfo *)NULL\n");
3292 printf("\treplacement points: %d\n",code->rplpointcount);
3294 printf("\ttotal allocations : %d\n",code->regalloccount);
3295 printf("\tsaved int regs : %d\n",code->savedintcount);
3296 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3297 #if defined(HAS_ADDRESS_REGISTER_FILE)
3298 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3300 printf("\tmemuse : %d\n",code->memuse);
3304 for (i=0; i<code->rplpointcount; ++i) {
3305 rp = code->rplpoints + i;
3308 parent = rp->parent;
3311 parent = parent->parent;
3313 replace_replacement_point_println(rp, depth);
3319 #if !defined(NDEBUG)
3320 static void java_value_print(s4 type, replace_val_t value)
3325 printf("%016llx",(unsigned long long) value.l);
3327 if (type < 0 || type > TYPE_RET)
3328 printf(" <INVALID TYPE:%d>", type);
3330 printf(" %s", show_jit_type_names[type]);
3332 if (type == TYPE_ADR && value.a != NULL) {
3335 utf_display_printable_ascii_classname(obj->vftbl->clazz->name);
3337 if (obj->vftbl->clazz == class_java_lang_String) {
3339 u = javastring_toutf(obj, false);
3340 utf_display_printable_ascii(u);
3344 else if (type == TYPE_INT) {
3345 printf(" %ld", (long) value.i);
3347 else if (type == TYPE_LNG) {
3348 printf(" %lld", (long long) value.l);
3350 else if (type == TYPE_FLT) {
3351 printf(" %f", value.f);
3353 else if (type == TYPE_DBL) {
3354 printf(" %f", value.d);
3357 #endif /* !defined(NDEBUG) */
3360 #if !defined(NDEBUG)
3361 void replace_source_frame_println(sourceframe_t *frame)
3366 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3367 printf("\tNATIVE\n");
3368 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3369 printf("\tnativepc: %p\n", frame->nativepc);
3370 printf("\tframesize: %d\n", frame->nativeframesize);
3373 for (i=0; i<INT_REG_CNT; ++i) {
3374 if (nregdescint[i] == REG_SAV)
3375 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3379 for (i=0; i<FLT_REG_CNT; ++i) {
3380 if (nregdescfloat[i] == REG_SAV)
3381 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3389 method_println(frame->method);
3390 printf("\tid: %d\n", frame->id);
3391 printf("\ttype: %s\n", replace_type_str[frame->type]);
3394 if (frame->instance.a) {
3395 printf("\tinstance: ");
3396 java_value_print(TYPE_ADR, frame->instance);
3400 if (frame->javalocalcount) {
3401 printf("\tlocals (%d):\n",frame->javalocalcount);
3402 for (i=0; i<frame->javalocalcount; ++i) {
3403 t = frame->javalocaltype[i];
3404 if (t == TYPE_VOID) {
3405 printf("\tlocal[ %2d] = void\n",i);
3408 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3409 java_value_print(t, frame->javalocals[i]);
3416 if (frame->javastackdepth) {
3417 printf("\tstack (depth %d):\n",frame->javastackdepth);
3418 for (i=0; i<frame->javastackdepth; ++i) {
3419 t = frame->javastacktype[i];
3420 if (t == TYPE_VOID) {
3421 printf("\tstack[%2d] = void", i);
3424 printf("\tstack[%2d] = ",i);
3425 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3432 if (frame->syncslotcount) {
3433 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3434 for (i=0; i<frame->syncslotcount; ++i) {
3435 printf("\tslot[%2d] = %016llx\n",i,(unsigned long long) frame->syncslots[i].p);
3440 if (frame->fromcode) {
3441 printf("\tfrom %p ", (void*)frame->fromcode);
3442 method_println(frame->fromcode->m);
3444 if (frame->tocode) {
3445 printf("\tto %p ", (void*)frame->tocode);
3446 method_println(frame->tocode->m);
3449 if (frame->fromrp) {
3450 printf("\tfrom replacement point:\n");
3451 replace_replacement_point_println(frame->fromrp, 2);
3454 printf("\tto replacement point:\n");
3455 replace_replacement_point_println(frame->torp, 2);
3460 #endif /* !defined(NDEBUG) */
3463 /* replace_sourcestate_println *************************************************
3468 ss...............the source state to print
3470 *******************************************************************************/
3472 #if !defined(NDEBUG)
3473 void replace_sourcestate_println(sourcestate_t *ss)
3476 sourceframe_t *frame;
3479 printf("(sourcestate_t *)NULL\n");
3483 printf("sourcestate_t:\n");
3485 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3486 printf(" frame %d:\n", i);
3487 replace_source_frame_println(frame);
3493 /* replace_sourcestate_println_short *******************************************
3495 Print a compact representation of the given source state.
3498 ss...............the source state to print
3500 *******************************************************************************/
3502 #if !defined(NDEBUG)
3503 void replace_sourcestate_println_short(sourcestate_t *ss)
3505 sourceframe_t *frame;
3507 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3510 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3511 printf("NATIVE (pc %p size %d) ",
3512 (void*)frame->nativepc, frame->nativeframesize);
3513 replace_stackframeinfo_println(frame->sfi);
3518 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3521 printf("%s", replace_type_str[frame->fromrp->type]);
3523 if (frame->torp && frame->torp->type != frame->fromrp->type)
3524 printf("->%s", replace_type_str[frame->torp->type]);
3526 if (frame->tocode != frame->fromcode)
3527 printf(" (%p->%p/%d) ",
3528 (void*) frame->fromcode, (void*) frame->tocode,
3531 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3533 method_println(frame->method);
3538 #if !defined(NDEBUG)
3539 static void replace_stackframeinfo_println(stackframeinfo_t *sfi)
3541 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3542 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3543 (void*)sfi->ra, (void*)sfi->xpc);
3546 method_println(sfi->code->m);
3554 * These are local overrides for various environment variables in Emacs.
3555 * Please do not remove this and leave it at the end of the file, where
3556 * Emacs will automagically detect them.
3557 * ---------------------------------------------------------------------
3560 * indent-tabs-mode: t
3564 * vim:noexpandtab:sw=4:ts=4: