1 /* src/vm/jit/replace.cpp - on-stack replacement of methods
3 Copyright (C) 1996-2005, 2006, 2007, 2008, 2009
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 = *((uint8_t**) ((intptr_t) basesp + LA_LR_OFFSET));
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)
1544 es->intregs[reg] = *((uintptr_t*) basesp);
1547 /* restore saved flt registers */
1551 for (i=0; i<es->code->savedfltcount; ++i) {
1552 while (nregdescfloat[--reg] != REG_SAV)
1554 basesp -= STACK_SLOTS_PER_FLOAT;
1555 es->fltregs[reg] = *((double*) basesp);
1558 #if defined(HAS_ADDRESS_REGISTER_FILE)
1559 /* restore saved adr registers */
1562 for (i=0; i<es->code->savedadrcount; ++i) {
1563 while (nregdescadr[--reg] != REG_SAV)
1566 es->adrregs[reg] = *((uintptr_t*) basesp);
1570 /* adjust the stackpointer */
1572 es->sp += framesize;
1573 #if STACKFRMAE_RA_BETWEEN_FRAMES
1574 es->sp += SIZEOF_VOID_P; /* skip return address */
1577 /* set the program counter to the return address */
1581 /* in debugging mode clobber non-saved registers */
1583 #if !defined(NDEBUG)
1585 for (i=0; i<INT_REG_CNT; ++i)
1586 if (nregdescint[i] != REG_SAV)
1587 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1588 for (i=0; i<FLT_REG_CNT; ++i)
1589 if (nregdescfloat[i] != REG_SAV)
1590 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1591 # if defined(HAS_ADDRESS_REGISTER_FILE)
1592 for (i=0; i<ADR_REG_CNT; ++i)
1593 if (nregdescadr[i] != REG_SAV)
1594 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1596 #endif /* !defined(NDEBUG) */
1600 /* md_push_stackframe **********************************************************
1602 Save the given return address, build the new stackframe,
1603 and store callee-saved registers.
1605 *** This function imitates the effects of a call and the ***
1606 *** method prolog of the callee. ***
1609 es...............execution state
1610 calleecode.......the code we are "calling"
1611 ra...............the return address to save
1614 *es..............the execution state after pushing the stack frame
1615 NOTE: es->pc, es->code, and es->pv are NOT updated.
1617 *******************************************************************************/
1619 void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra)
1623 stackslot_t *basesp;
1629 /* write the return address */
1631 #if STACKFRMAE_RA_BETWEEN_FRAMES
1632 es->sp -= SIZEOF_VOID_P;
1633 *((void **)es->sp) = (void *) ra;
1634 if (calleecode->stackframesize)
1635 es->sp -= (SIZE_OF_STACKSLOT - SIZEOF_VOID_P);
1636 #endif /* STACKFRAME_RA_BETWEEN_FRAMES */
1638 es->ra = (u1*) (ptrint) ra;
1640 /* build the stackframe */
1642 DOLOG( printf("building stackframe of %d words at %p\n",
1643 calleecode->stackframesize, (void*)es->sp); );
1645 sp = (stackslot_t *) es->sp;
1648 sp -= calleecode->stackframesize;
1651 /* in debug mode, invalidate stack frame first */
1653 /* XXX may not invalidate linkage area used by native code! */
1655 #if !defined(NDEBUG) && 0
1656 for (i=0; i< (basesp - sp) && i < 1; ++i) {
1657 sp[i] = 0xdeaddeadU;
1661 #if defined(__I386__)
1662 /* Stackslot 0 may contain the object instance for vftbl patching.
1663 Destroy it, so there's no undefined value used. */
1664 if ((basesp - sp) > 0) {
1669 /* save the return address register */
1671 #if STACKFRAME_RA_TOP_OF_FRAME
1672 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
1673 if (!code_is_leafmethod(calleecode))
1675 *--basesp = (ptrint) ra;
1676 #endif /* STACKFRAME_RA_TOP_OF_FRAME */
1678 #if defined(REPLACE_RA_LINKAGE_AREA)
1679 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
1680 if (!code_is_leafmethod(calleecode))
1682 *((uint8_t**) ((intptr_t) basesp + LA_LR_OFFSET)) = ra;
1683 #endif /* REPLACE_RA_LINKAGE_AREA */
1685 /* save int registers */
1688 for (i=0; i<calleecode->savedintcount; ++i) {
1689 while (nregdescint[--reg] != REG_SAV)
1692 *((uintptr_t*) basesp) = es->intregs[reg];
1694 /* XXX may not clobber saved regs used by native code! */
1695 #if !defined(NDEBUG) && 0
1696 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1700 /* save flt registers */
1704 for (i=0; i<calleecode->savedfltcount; ++i) {
1705 while (nregdescfloat[--reg] != REG_SAV)
1707 basesp -= STACK_SLOTS_PER_FLOAT;
1708 *((double*) basesp) = es->fltregs[reg];
1710 /* XXX may not clobber saved regs used by native code! */
1711 #if !defined(NDEBUG) && 0
1712 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1716 #if defined(HAS_ADDRESS_REGISTER_FILE)
1717 /* save adr registers */
1720 for (i=0; i<calleecode->savedadrcount; ++i) {
1721 while (nregdescadr[--reg] != REG_SAV)
1724 *((uintptr_t*) basesp) = es->adrregs[reg];
1726 /* XXX may not clobber saved regs used by native code! */
1727 #if !defined(NDEBUG) && 0
1728 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1735 /* replace_pop_activation_record ***********************************************
1737 Peel a stack frame from the execution state.
1739 *** This function imitates the effects of the method epilog ***
1740 *** and returning from the method call. ***
1743 es...............execution state
1744 frame............source frame, receives synchronization slots
1747 *es..............the execution state after popping the stack frame
1750 the return address of the poped activation record
1752 *******************************************************************************/
1754 u1* replace_pop_activation_record(executionstate_t *es,
1755 sourceframe_t *frame)
1766 /* calculate the base of the stack frame */
1768 sp = (stackslot_t *) es->sp;
1769 assert(frame->syncslotcount == 0);
1770 assert(frame->syncslots == NULL);
1771 count = code_get_sync_slot_count(es->code);
1772 frame->syncslotcount = count;
1773 frame->syncslots = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1774 for (i=0; i<count; ++i) {
1775 frame->syncslots[i].p = *((intptr_t*) (sp + es->code->memuse + i)); /* XXX md_ function */
1778 /* pop the stackframe */
1780 md_pop_stackframe(es);
1784 DOLOG( printf("RA = %p\n", (void*)ra); );
1786 /* Subtract one from the PC so we do not hit the replacement point */
1787 /* of the instruction following the call, if there is one. */
1791 /* find the new codeinfo */
1793 void* pv = md_codegen_get_pv_from_pc(ra);
1794 DOLOG( printf("PV = %p\n", pv); );
1796 code = code_get_codeinfo_for_pv(pv);
1797 DOLOG( printf("CODE = %p\n", (void*) code); );
1799 /* return NULL if we reached native code */
1801 es->pv = (uint8_t*) pv;
1804 return (code) ? ra : NULL;
1808 /* replace_patch_method_pointer ************************************************
1810 Patch a method pointer (may be in code, data segment, vftbl, or interface
1814 mpp..............address of the method pointer to patch
1815 entrypoint.......the new entrypoint of the method
1816 kind.............kind of call to patch, used only for debugging
1818 *******************************************************************************/
1820 static void replace_patch_method_pointer(methodptr *mpp,
1821 methodptr entrypoint,
1824 #if !defined(NDEBUG)
1829 DOLOG( printf("patch method pointer from: %p to %p\n",
1830 (void*) *mpp, (void*)entrypoint); );
1832 #if !defined(NDEBUG)
1833 oldcode = code_get_codeinfo_for_pv(*mpp);
1834 newcode = code_get_codeinfo_for_pv(entrypoint);
1836 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1837 method_println(oldcode->m);
1838 printf("\t with %p ", (void*) newcode);
1839 method_println(newcode->m); );
1841 assert(oldcode->m == newcode->m);
1844 /* write the new entrypoint */
1846 *mpp = (methodptr) entrypoint;
1850 /* replace_patch_class *********************************************************
1852 Patch a method in the given class.
1855 vftbl............vftbl of the class
1856 m................the method to patch
1857 oldentrypoint....the old entrypoint to replace
1858 entrypoint.......the new entrypoint
1860 *******************************************************************************/
1862 void replace_patch_class(vftbl_t *vftbl,
1871 /* patch the vftbl of the class */
1873 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1877 /* patch the interface tables */
1879 assert(oldentrypoint);
1881 for (i=0; i < vftbl->interfacetablelength; ++i) {
1882 mpp = vftbl->interfacetable[-i];
1883 mppend = mpp + vftbl->interfacevftbllength[i];
1884 for (; mpp != mppend; ++mpp)
1885 if (*mpp == oldentrypoint) {
1886 replace_patch_method_pointer(mpp, entrypoint, "interface");
1892 /* replace_patch_class_hierarchy ***********************************************
1894 Patch a method in all loaded classes.
1897 m................the method to patch
1898 oldentrypoint....the old entrypoint to replace
1899 entrypoint.......the new entrypoint
1901 *******************************************************************************/
1903 struct replace_patch_data_t {
1909 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1911 vftbl_t *vftbl = c->vftbl;
1914 && vftbl->vftbllength > pd->m->vftblindex
1915 && (void*) vftbl->table[pd->m->vftblindex] != (void*) (uintptr_t) &asm_abstractmethoderror
1916 && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
1918 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1922 void replace_patch_class_hierarchy(methodinfo *m,
1926 struct replace_patch_data_t pd;
1929 pd.oldentrypoint = oldentrypoint;
1930 pd.entrypoint = entrypoint;
1932 DOLOG_SHORT( printf("patching class hierarchy: ");
1933 method_println(m); );
1935 classcache_foreach_loaded_class(
1936 (classcache_foreach_functionptr_t) &replace_patch_callback,
1941 /* replace_patch_future_calls **************************************************
1943 Analyse a call site and depending on the kind of call patch the call, the
1944 virtual function table, or the interface table.
1947 ra...............return address pointing after the call site
1948 callerframe......source frame of the caller
1949 calleeframe......source frame of the callee, must have been mapped
1951 *******************************************************************************/
1953 void replace_patch_future_calls(u1 *ra,
1954 sourceframe_t *callerframe,
1955 sourceframe_t *calleeframe)
1958 methodptr entrypoint;
1959 methodptr oldentrypoint;
1962 codeinfo *calleecode;
1963 methodinfo *calleem;
1968 assert(callerframe->down == calleeframe);
1970 /* get the new codeinfo and the method that shall be entered */
1972 calleecode = calleeframe->tocode;
1975 calleem = calleeframe->method;
1976 assert(calleem == calleecode->m);
1978 entrypoint = (methodptr) calleecode->entrypoint;
1980 /* check if we are at an method entry rplpoint at the innermost frame */
1982 atentry = (calleeframe->down == NULL)
1983 && !(calleem->flags & ACC_STATIC)
1984 && (calleeframe->fromrp->id == 0); /* XXX */
1986 /* get the position to patch, in case it was a statically bound call */
1988 pv = callerframe->fromcode->entrypoint;
1989 patchpos = (u1*) md_jit_method_patch_address(pv, ra, NULL);
1991 if (patchpos == NULL) {
1992 /* the call was dispatched dynamically */
1994 /* we can only patch such calls if we are at the entry point */
1996 #if !defined(__I386__)
1997 /* On i386 we always know the instance argument. */
2002 assert((calleem->flags & ACC_STATIC) == 0);
2004 oldentrypoint = calleeframe->fromcode->entrypoint;
2006 /* we need to know the instance */
2008 if (!calleeframe->instance.a) {
2009 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
2010 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
2016 obj = calleeframe->instance.a;
2019 assert(vftbl->clazz->vftbl == vftbl);
2021 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->clazz); );
2023 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
2026 /* the call was statically bound */
2028 #if defined(__I386__)
2029 /* It happens that there is a patcher trap. (pm) */
2030 if (*(u2 *)(patchpos - 1) == 0x0b0f) {
2033 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
2038 /* replace_push_activation_record **********************************************
2040 Push a stack frame onto the execution state.
2042 *** This function imitates the effects of a call and the ***
2043 *** method prolog of the callee. ***
2046 es...............execution state
2047 rpcall...........the replacement point at the call site
2048 callerframe......source frame of the caller, or NULL for creating the
2050 calleeframe......source frame of the callee, must have been mapped
2053 *es..............the execution state after pushing the stack frame
2055 *******************************************************************************/
2057 void replace_push_activation_record(executionstate_t *es,
2059 sourceframe_t *callerframe,
2060 sourceframe_t *calleeframe)
2066 codeinfo *calleecode;
2069 assert(!rpcall || callerframe);
2070 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
2071 assert(!rpcall || rpcall == callerframe->torp);
2072 assert(calleeframe);
2073 assert(!callerframe || calleeframe == callerframe->down);
2075 /* the compilation unit we are entering */
2077 calleecode = calleeframe->tocode;
2080 /* calculate the return address */
2083 ra = rpcall->pc + rpcall->callsize;
2085 ra = es->pc + 1 /* XXX this is ugly */;
2087 /* push the stackframe */
2089 md_push_stackframe(es, calleecode, ra);
2091 /* we move into a new code unit, set code, PC, PV */
2093 es->code = calleecode;
2094 es->pc = calleecode->entrypoint; /* XXX not needed? */
2095 es->pv = calleecode->entrypoint;
2097 /* write slots used for synchronization */
2099 sp = (stackslot_t *) es->sp;
2100 count = code_get_sync_slot_count(calleecode);
2101 assert(count == calleeframe->syncslotcount);
2102 for (i=0; i<count; ++i) {
2103 *((intptr_t*) (sp + calleecode->memuse + i)) = calleeframe->syncslots[i].p;
2106 /* redirect future invocations */
2108 if (callerframe && rpcall) {
2109 #if defined(REPLACE_PATCH_ALL)
2110 if (rpcall->type == callerframe->fromrp->type)
2112 if (rpcall == callerframe->fromrp)
2114 replace_patch_future_calls(ra, callerframe, calleeframe);
2119 /* replace_find_replacement_point **********************************************
2121 Find the replacement point in the given code corresponding to the
2122 position given in the source frame.
2125 code.............the codeinfo in which to search the rplpoint
2126 frame............the source frame defining the position to look for
2127 parent...........parent replacement point to match
2130 the replacement point
2132 *******************************************************************************/
2134 rplpoint * replace_find_replacement_point(codeinfo *code,
2135 sourceframe_t *frame,
2148 DOLOG( printf("searching replacement point for:\n");
2149 replace_source_frame_println(frame); );
2153 DOLOG( printf("code = %p\n", (void*)code); );
2155 rp = code->rplpoints;
2156 i = code->rplpointcount;
2158 if (rp->id == frame->id && rp->method == frame->method
2159 && rp->parent == parent
2160 && replace_normalize_type_map[rp->type] == frame->type)
2162 /* check if returnAddresses match */
2163 /* XXX optimize: only do this if JSRs in method */
2164 DOLOG( printf("checking match for:");
2165 replace_replacement_point_println(rp, 1); fflush(stdout); );
2168 for (j = rp->regalloccount; j--; ++ra) {
2169 if (ra->type == TYPE_RET) {
2170 if (ra->index == RPLALLOC_STACK) {
2171 assert(stacki < frame->javastackdepth);
2172 if (frame->javastack[stacki].i != ra->regoff)
2177 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2178 if (frame->javalocals[ra->index].i != ra->regoff)
2191 #if !defined(NDEBUG)
2192 printf("candidate replacement points were:\n");
2193 rp = code->rplpoints;
2194 i = code->rplpointcount;
2196 replace_replacement_point_println(rp, 1);
2200 vm_abort("no matching replacement point found");
2201 return NULL; /* NOT REACHED */
2205 /* replace_find_replacement_point_for_pc ***************************************
2207 Find the nearest replacement point at or before the given PC. The
2208 given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
2209 the replacement point to be found.
2212 code.............compilation unit the PC is in
2213 pc...............the machine code PC
2216 the replacement point found, or
2217 NULL if no replacement point was found
2219 *******************************************************************************/
2221 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc, unsigned desired_flags)
2227 DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
2228 method_println(code->m); );
2232 rp = code->rplpoints;
2233 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2234 DOLOG( replace_replacement_point_println(rp, 2); );
2235 if (rp->pc <= pc && rp->pc + rp->callsize >= pc) {
2236 if (desired_flags) {
2237 if (rp->flags & desired_flags) {
2249 /* replace_pop_native_frame ****************************************************
2251 Unroll a native frame in the execution state and create a source frame
2255 es...............current execution state
2256 ss...............the current source state
2257 sfi..............stackframeinfo for the native frame
2260 es...............execution state after unrolling the native frame
2261 ss...............gets the added native source frame
2263 *******************************************************************************/
2265 static void replace_pop_native_frame(executionstate_t *es,
2267 stackframeinfo_t *sfi)
2269 sourceframe_t *frame;
2275 frame = replace_new_sourceframe(ss);
2279 /* remember pc and size of native frame */
2281 frame->nativepc = es->pc;
2282 frame->nativeframesize = (es->sp != 0) ? (((uintptr_t) sfi->sp) - ((uintptr_t) es->sp)) : 0;
2283 assert(frame->nativeframesize >= 0);
2285 /* remember values of saved registers */
2288 for (i=0; i<INT_REG_CNT; ++i) {
2289 if (nregdescint[i] == REG_SAV)
2290 frame->nativesavint[j++] = es->intregs[i];
2294 for (i=0; i<FLT_REG_CNT; ++i) {
2295 if (nregdescfloat[i] == REG_SAV)
2296 frame->nativesavflt[j++] = es->fltregs[i];
2299 #if defined(HAS_ADDRESS_REGISTER_FILE)
2301 for (i=0; i<ADR_REG_CNT; ++i) {
2302 if (nregdescadr[i] == REG_SAV)
2303 frame->nativesavadr[j++] = es->adrregs[i];
2307 /* restore saved registers */
2309 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2311 for (i=0; i<INT_REG_CNT; ++i) {
2312 if (nregdescint[i] == REG_SAV)
2313 es->intregs[i] = sfi->intregs[j++];
2316 /* XXX we don't have them, yet, in the sfi, so clear them */
2318 for (i=0; i<INT_REG_CNT; ++i) {
2319 if (nregdescint[i] == REG_SAV)
2324 /* XXX we don't have float registers in the sfi, so clear them */
2326 for (i=0; i<FLT_REG_CNT; ++i) {
2327 if (nregdescfloat[i] == REG_SAV)
2328 es->fltregs[i] = 0.0;
2331 #if defined(HAS_ADDRESS_REGISTER_FILE)
2332 # if defined(ENABLE_GC_CACAO)
2334 for (i=0; i<ADR_REG_CNT; ++i) {
2335 if (nregdescadr[i] == REG_SAV)
2336 es->adrregs[i] = sfi->adrregs[j++];
2339 for (i=0; i<ADR_REG_CNT; ++i) {
2340 if (nregdescadr[i] == REG_SAV)
2346 /* restore codeinfo of the native stub */
2348 code = code_get_codeinfo_for_pv(sfi->pv);
2350 /* restore sp, pv, pc and codeinfo of the parent method */
2352 es->sp = (uint8_t*) (((uintptr_t) sfi->sp) + md_stacktrace_get_framesize(code));
2353 #if STACKFRMAE_RA_BETWEEN_FRAMES
2354 es->sp += SIZEOF_VOID_P; /* skip return address */
2356 es->pv = (uint8_t*) md_codegen_get_pv_from_pc(sfi->ra);
2357 es->pc = (uint8_t*) (((uintptr_t) ((sfi->xpc) ? sfi->xpc : sfi->ra)) - 1);
2358 es->code = code_get_codeinfo_for_pv(es->pv);
2362 /* replace_push_native_frame ***************************************************
2364 Rebuild a native frame onto the execution state and remove its source frame.
2366 Note: The native frame is "rebuild" by setting fields like PC and stack
2367 pointer in the execution state accordingly. Values in the
2368 stackframeinfo may be modified, but the actual stack frame of the
2369 native code is not touched.
2372 es...............current execution state
2373 ss...............the current source state
2376 es...............execution state after re-rolling the native frame
2377 ss...............the native source frame is removed
2379 *******************************************************************************/
2381 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2383 sourceframe_t *frame;
2389 DOLOG( printf("pushing native frame\n"); );
2391 /* remove the frame from the source state */
2395 assert(REPLACE_IS_NATIVE_FRAME(frame));
2397 ss->frames = frame->down;
2399 /* skip sp for the native stub */
2401 es->sp -= md_stacktrace_get_framesize(frame->sfi->code);
2402 #if STACKFRMAE_RA_BETWEEN_FRAMES
2403 es->sp -= SIZEOF_VOID_P; /* skip return address */
2406 /* assert that the native frame has not moved */
2408 assert(es->sp == frame->sfi->sp);
2410 /* update saved registers in the stackframeinfo */
2412 #if defined(ENABLE_GC_CACAO)
2414 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2415 for (i=0; i<INT_REG_CNT; ++i) {
2416 if (nregdescint[i] == REG_SAV)
2417 frame->sfi->intregs[j++] = es->intregs[i];
2420 for (i=0; i<ADR_REG_CNT; ++i) {
2421 if (nregdescadr[i] == REG_SAV)
2422 frame->sfi->adrregs[j++] = es->adrregs[i];
2426 /* XXX leave float registers untouched here */
2429 /* restore saved registers */
2432 for (i=0; i<INT_REG_CNT; ++i) {
2433 if (nregdescint[i] == REG_SAV)
2434 es->intregs[i] = frame->nativesavint[j++];
2438 for (i=0; i<FLT_REG_CNT; ++i) {
2439 if (nregdescfloat[i] == REG_SAV)
2440 es->fltregs[i] = frame->nativesavflt[j++];
2443 #if defined(HAS_ADDRESS_REGISTER_FILE)
2445 for (i=0; i<ADR_REG_CNT; ++i) {
2446 if (nregdescadr[i] == REG_SAV)
2447 es->adrregs[i] = frame->nativesavadr[j++];
2451 /* skip the native frame on the machine stack */
2453 es->sp -= frame->nativeframesize;
2455 /* set the pc the next frame must return to */
2457 es->pc = frame->nativepc;
2461 /* replace_recover_source_state ************************************************
2463 Recover the source state from the given replacement point and execution
2467 rp...............replacement point that has been reached, if any
2468 sfi..............stackframeinfo, if called from native code
2469 es...............execution state at the replacement point rp
2474 *******************************************************************************/
2476 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2477 stackframeinfo_t *sfi,
2478 executionstate_t *es)
2483 #if defined(REPLACE_STATISTICS)
2487 /* create the source frame structure in dump memory */
2489 ss = (sourcestate_t*) DumpMemory::allocate(sizeof(sourcestate_t));
2492 /* each iteration of the loop recovers one source frame */
2499 DOLOG( executionstate_println(es); );
2501 /* if we are not at a replacement point, it is a native frame */
2504 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2507 replace_pop_native_frame(es, ss, sfi);
2510 if (es->code == NULL)
2513 goto after_machine_frame;
2516 /* read the values for this source frame from the execution state */
2518 DOLOG( printf("recovering source state for%s:\n",
2519 (ss->frames == NULL) ? " TOPFRAME" : "");
2520 replace_replacement_point_println(rp, 1); );
2522 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2524 #if defined(ENABLE_VMLOG)
2525 vmlog_cacao_unrol_method(ss->frames->method);
2528 #if defined(REPLACE_STATISTICS)
2529 REPLACE_COUNT(stat_frames);
2531 replace_statistics_source_frame(ss->frames);
2534 /* in locked areas (below native frames), identity map the frame */
2537 ss->frames->torp = ss->frames->fromrp;
2538 ss->frames->tocode = ss->frames->fromcode;
2541 /* unroll to the next (outer) frame */
2544 /* this frame is in inlined code */
2546 DOLOG( printf("INLINED!\n"); );
2550 assert(rp->type == RPLPOINT_TYPE_INLINE);
2551 REPLACE_COUNT(stat_unroll_inline);
2554 /* this frame had been called at machine-level. pop it. */
2556 DOLOG( printf("UNWIND\n"); );
2558 ra = replace_pop_activation_record(es, ss->frames);
2560 DOLOG( printf("REACHED NATIVE CODE\n"); );
2564 #if !defined(ENABLE_GC_CACAO)
2565 break; /* XXX remove to activate native frames */
2570 /* find the replacement point at the call site */
2572 after_machine_frame:
2573 rp = replace_find_replacement_point_for_pc(es->code, es->pc, 0);
2576 vm_abort("could not find replacement point while unrolling call");
2578 DOLOG( printf("found replacement point.\n");
2579 replace_replacement_point_println(rp, 1); );
2581 assert(rp->type == RPLPOINT_TYPE_CALL);
2582 REPLACE_COUNT(stat_unroll_call);
2584 } /* end loop over source frames */
2586 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2592 /* replace_map_source_state ****************************************************
2594 Map each source frame in the given source state to a target replacement
2595 point and compilation unit. If no valid code is available for a source
2596 frame, it is (re)compiled.
2599 ss...............the source state
2602 ss...............the source state, modified: The `torp` and `tocode`
2603 fields of each source frame are set.
2606 true.............everything went ok
2607 false............an exception has been thrown
2609 *******************************************************************************/
2611 static bool replace_map_source_state(sourcestate_t *ss)
2613 sourceframe_t *frame;
2616 rplpoint *parent; /* parent of inlined rplpoint */
2617 #if defined(REPLACE_STATISTICS)
2624 /* iterate over the source frames from outermost to innermost */
2626 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2628 /* XXX skip native frames */
2630 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2635 /* map frames which are not already mapped */
2637 if (frame->tocode) {
2638 code = frame->tocode;
2643 assert(frame->torp == NULL);
2645 if (parent == NULL) {
2646 /* find code for this frame */
2648 #if defined(REPLACE_STATISTICS)
2649 oldcode = frame->method->code;
2651 /* request optimization of hot methods and their callers */
2653 if (frame->method->hitcountdown < 0
2654 || (frame->down && frame->down->method->hitcountdown < 0))
2655 jit_request_optimization(frame->method);
2657 code = jit_get_current_code(frame->method);
2660 return false; /* exception */
2662 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2667 /* map this frame */
2669 rp = replace_find_replacement_point(code, frame, parent);
2671 frame->tocode = code;
2675 if (rp->type == RPLPOINT_TYPE_CALL) {
2688 /* replace_map_source_state_identity *******************************************
2690 Map each source frame in the given source state to the same replacement
2691 point and compilation unit it was derived from. This is mainly used for
2695 ss...............the source state
2698 ss...............the source state, modified: The `torp` and `tocode`
2699 fields of each source frame are set.
2701 *******************************************************************************/
2703 #if defined(ENABLE_GC_CACAO)
2704 static void replace_map_source_state_identity(sourcestate_t *ss)
2706 sourceframe_t *frame;
2708 /* iterate over the source frames from outermost to innermost */
2710 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2712 /* skip native frames */
2714 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2718 /* map frames using the identity mapping */
2720 if (frame->tocode) {
2721 assert(frame->tocode == frame->fromcode);
2722 assert(frame->torp == frame->fromrp);
2724 assert(frame->tocode == NULL);
2725 assert(frame->torp == NULL);
2726 frame->tocode = frame->fromcode;
2727 frame->torp = frame->fromrp;
2734 /* replace_build_execution_state ***********************************************
2736 Build an execution state for the given (mapped) source state.
2738 !!! CAUTION: This function rewrites the machine stack !!!
2740 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2743 ss...............the source state. Must have been mapped by
2744 replace_map_source_state before.
2745 es...............the base execution state on which to build
2748 *es..............the new execution state
2750 *******************************************************************************/
2752 static void replace_build_execution_state(sourcestate_t *ss,
2753 executionstate_t *es)
2756 sourceframe_t *prevframe;
2763 while (ss->frames) {
2765 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2766 prevframe = ss->frames;
2767 replace_push_native_frame(es, ss);
2773 if (parent == NULL) {
2774 /* create a machine-level stack frame */
2776 DOLOG( printf("pushing activation record for:\n");
2777 if (rp) replace_replacement_point_println(rp, 1);
2778 else printf("\tfirst frame\n"); );
2780 replace_push_activation_record(es, rp, prevframe, ss->frames);
2782 DOLOG( executionstate_println(es); );
2785 rp = ss->frames->torp;
2788 DOLOG( printf("creating execution state for%s:\n",
2789 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2790 replace_replacement_point_println(ss->frames->fromrp, 1);
2791 replace_replacement_point_println(rp, 1); );
2793 es->code = ss->frames->tocode;
2794 prevframe = ss->frames;
2796 #if defined(ENABLE_VMLOG)
2797 vmlog_cacao_rerol_method(ss->frames->method);
2800 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2802 DOLOG( executionstate_println(es); );
2804 if (rp->type == RPLPOINT_TYPE_CALL) {
2815 /* replace_me ******************************************************************
2817 This function is called by the signal handler when a thread reaches
2818 a replacement point. `replace_me` must map the execution state to the
2819 target replacement point and let execution continue there.
2821 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2824 rp...............replacement point that has been reached
2825 es...............execution state read by signal handler
2827 *******************************************************************************/
2829 static void replace_me(rplpoint *rp, executionstate_t *es)
2831 stackframeinfo_t *sfi;
2833 sourceframe_t *frame;
2836 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2837 threadobject *thread;
2840 origcode = es->code;
2843 #if defined(ENABLE_TLH)
2844 /*printf("Replacing in %s/%s\n", rp->method->clazz->name->text, rp->method->name->text);*/
2847 /*if (strcmp(rp->method->clazz->name->text, "antlr/AlternativeElement") == 0 && strcmp(rp->method->name->text, "getAutoGenType") ==0) opt_TraceReplacement = 2; else opt_TraceReplacement = 0;*/
2849 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2850 stat_replacements, (void*)THREADOBJECT,
2852 method_println(es->code->m); );
2854 DOLOG( replace_replacement_point_println(rp, 1); );
2856 REPLACE_COUNT(stat_replacements);
2858 // Create new dump memory area.
2861 /* Get the stackframeinfo for the current thread. */
2863 sfi = threads_get_current_stackframeinfo();
2865 /* recover source state */
2867 ss = replace_recover_source_state(rp, sfi, es);
2869 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2870 /* if there is a collection pending, we assume the replacement point should
2871 suspend this thread */
2875 thread = THREADOBJECT;
2877 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2879 /* map the sourcestate using the identity mapping */
2880 replace_map_source_state_identity(ss);
2882 /* since we enter the same method again, we turn off rps now */
2883 /* XXX michi: can we really do this? what if the rp was active before
2884 we activated it for the gc? */
2885 replace_deactivate_replacement_points(origcode);
2887 /* remember executionstate and sourcestate for this thread */
2888 GC_EXECUTIONSTATE = es;
2889 GC_SOURCESTATE = ss;
2891 /* really suspend this thread now (PC = 0) */
2892 threads_suspend_ack(NULL, NULL);
2894 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2897 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2899 /* map the source state */
2901 if (!replace_map_source_state(ss))
2902 vm_abort("exception during method replacement");
2904 DOLOG( replace_sourcestate_println(ss); );
2906 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2908 #if !defined(NDEBUG)
2909 /* avoid infinite loops by self-replacement, only if not in testing mode */
2911 if (!opt_TestReplacement) {
2914 frame = frame->down;
2916 if (frame->torp == origrp) {
2918 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2920 replace_deactivate_replacement_points(origcode);
2925 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2929 /* build the new execution state */
2931 replace_build_execution_state(ss, es);
2933 #if !defined(NDEBUG)
2934 /* continue execution after patched machine code, if testing mode enabled */
2936 if (opt_TestReplacement)
2937 es->pc += REPLACEMENT_PATCH_SIZE;
2942 /* replace_handler *************************************************************
2944 This function is called by the signal handler. It determines if there
2945 is an active replacement point pending at the given PC and returns
2948 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2951 pc...............the program counter that triggered the replacement.
2952 es...............the execution state (machine state) to which the
2953 replacement should be applied.
2956 es...............the execution state after replacement finished.
2959 true.............replacement done, everything went ok
2960 false............no replacement done, execution state unchanged
2962 *******************************************************************************/
2964 bool replace_handler(u1 *pc, executionstate_t *es)
2968 #if defined(ENABLE_RT_TIMING)
2969 struct timespec time_start, time_end;
2972 /* search the codeinfo for the given PC */
2974 code = code_find_codeinfo_for_pc(pc);
2977 /* search for a replacement point at the given PC */
2979 rp = replace_find_replacement_point_for_pc(code, pc, (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN));
2981 /* check if the replacement point belongs to given PC and is active */
2983 if ((rp != NULL) && (rp->pc == pc)
2984 && (rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))) {
2986 DOLOG( printf("valid replacement point\n"); );
2988 /* set codeinfo pointer in execution state */
2992 /* do the actual replacement */
2994 #if defined(ENABLE_RT_TIMING)
2995 RT_TIMING_GET_TIME(time_start);
3000 #if defined(ENABLE_RT_TIMING)
3001 RT_TIMING_GET_TIME(time_end);
3002 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_REPLACE);
3005 /* new code is entered after returning */
3007 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
3015 /******************************************************************************/
3016 /* NOTE: Stuff specific to the exact GC is below. */
3017 /******************************************************************************/
3019 #if defined(ENABLE_GC_CACAO)
3020 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
3022 stackframeinfo_t *sfi;
3023 executionstate_t *es;
3026 /* Get the stackframeinfo of this thread. */
3028 assert(thread == THREADOBJECT);
3030 sfi = threads_get_current_stackframeinfo();
3032 /* create the execution state */
3033 es = (executionstate_t*) DumpMemory::allocate(sizeof(executionstate_t));
3036 es->pv = 0; /* since we are in a native, PV is invalid! */
3037 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
3039 /* we assume we are in a native (no replacement point)! */
3040 ss = replace_recover_source_state(NULL, sfi, es);
3042 /* map the sourcestate using the identity mapping */
3043 replace_map_source_state_identity(ss);
3045 /* remember executionstate and sourcestate for this thread */
3046 GC_EXECUTIONSTATE = es;
3047 GC_SOURCESTATE = ss;
3051 #if defined(ENABLE_GC_CACAO)
3052 void replace_gc_into_native(threadobject *thread)
3054 executionstate_t *es;
3057 /* get the executionstate and sourcestate for the given thread */
3058 es = GC_EXECUTIONSTATE;
3059 ss = GC_SOURCESTATE;
3061 /* rebuild the stack of the given thread */
3062 replace_build_execution_state(ss, es);
3067 /******************************************************************************/
3068 /* NOTE: No important code below. */
3069 /******************************************************************************/
3072 /* statistics *****************************************************************/
3074 #if defined(REPLACE_STATISTICS)
3075 static void print_freq(FILE *file,int *array,int limit)
3080 for (i=0; i<limit; ++i)
3082 sum += array[limit];
3083 for (i=0; i<limit; ++i) {
3085 fprintf(file," %3d: %8d (cum %3d%%)\n",
3086 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3088 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3090 #endif /* defined(REPLACE_STATISTICS) */
3093 #if defined(REPLACE_STATISTICS)
3095 #define REPLACE_PRINT_DIST(name, array) \
3096 printf(" " name " distribution:\n"); \
3097 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3099 void replace_print_statistics(void)
3101 printf("replacement statistics:\n");
3102 printf(" # of replacements: %d\n", stat_replacements);
3103 printf(" # of frames: %d\n", stat_frames);
3104 printf(" # of recompilations: %d\n", stat_recompile);
3105 printf(" patched static calls:%d\n", stat_staticpatch);
3106 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3107 printf(" unrolled calls: %d\n", stat_unroll_call);
3108 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3109 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3110 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3111 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3112 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3113 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3114 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3115 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3116 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3117 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3119 printf(" # of methods: %d\n", stat_methods);
3120 printf(" # of replacement points: %d\n", stat_rploints);
3121 printf(" # of regallocs: %d\n", stat_regallocs);
3122 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3123 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3124 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3128 #endif /* defined(REPLACE_STATISTICS) */
3131 #if defined(REPLACE_STATISTICS)
3132 static void replace_statistics_source_frame(sourceframe_t *frame)
3141 for (i=0; i<frame->javalocalcount; ++i) {
3142 switch (frame->javalocaltype[i]) {
3143 case TYPE_ADR: adr++; break;
3144 case TYPE_RET: ret++; break;
3145 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3146 case TYPE_VOID: vd++; break;
3151 REPLACE_COUNT_DIST(stat_dist_locals, n);
3152 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3153 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3154 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3155 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3156 adr = ret = prim = n = 0;
3157 for (i=0; i<frame->javastackdepth; ++i) {
3158 switch (frame->javastacktype[i]) {
3159 case TYPE_ADR: adr++; break;
3160 case TYPE_RET: ret++; break;
3161 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3165 REPLACE_COUNT_DIST(stat_dist_stack, n);
3166 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3167 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3168 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3170 #endif /* defined(REPLACE_STATISTICS) */
3173 /* debugging helpers **********************************************************/
3175 /* replace_replacement_point_println *******************************************
3177 Print replacement point info.
3180 rp...............the replacement point to print
3182 *******************************************************************************/
3184 #if !defined(NDEBUG)
3186 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3188 static const char *replace_type_str[] = {
3198 void replace_replacement_point_println(rplpoint *rp, int depth)
3204 printf("(rplpoint *)NULL\n");
3208 for (j=0; j<depth; ++j)
3211 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3212 rp->id, (void*)rp,rp->pc,rp->callsize,
3213 replace_type_str[rp->type]);
3214 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3216 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3217 printf(" COUNTDOWN");
3218 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3220 printf(" parent:%p\n", (void*)rp->parent);
3221 for (j=0; j<depth; ++j)
3223 printf("ra:%d = [", rp->regalloccount);
3225 for (j=0; j<rp->regalloccount; ++j) {
3228 index = rp->regalloc[j].index;
3230 case RPLALLOC_STACK: printf("S"); break;
3231 case RPLALLOC_PARAM: printf("P"); break;
3232 case RPLALLOC_SYNC : printf("Y"); break;
3233 default: printf("%d", index);
3235 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3236 if (rp->regalloc[j].type == TYPE_RET) {
3237 printf("ret(L%03d)", rp->regalloc[j].regoff);
3240 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3245 for (j=0; j<depth; ++j)
3248 method_print(rp->method);
3252 #endif /* !defined(NDEBUG) */
3255 /* replace_show_replacement_points *********************************************
3257 Print replacement point info.
3260 code.............codeinfo whose replacement points should be printed.
3262 *******************************************************************************/
3264 #if !defined(NDEBUG)
3265 void replace_show_replacement_points(codeinfo *code)
3273 printf("(codeinfo *)NULL\n");
3277 printf("\treplacement points: %d\n",code->rplpointcount);
3279 printf("\ttotal allocations : %d\n",code->regalloccount);
3280 printf("\tsaved int regs : %d\n",code->savedintcount);
3281 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3282 #if defined(HAS_ADDRESS_REGISTER_FILE)
3283 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3285 printf("\tmemuse : %d\n",code->memuse);
3289 for (i=0; i<code->rplpointcount; ++i) {
3290 rp = code->rplpoints + i;
3293 parent = rp->parent;
3296 parent = parent->parent;
3298 replace_replacement_point_println(rp, depth);
3304 #if !defined(NDEBUG)
3305 static void java_value_print(s4 type, replace_val_t value)
3310 printf("%016llx",(unsigned long long) value.l);
3312 if (type < 0 || type > TYPE_RET)
3313 printf(" <INVALID TYPE:%d>", type);
3315 printf(" %s", show_jit_type_names[type]);
3317 if (type == TYPE_ADR && value.a != NULL) {
3320 utf_display_printable_ascii_classname(obj->vftbl->clazz->name);
3322 if (obj->vftbl->clazz == class_java_lang_String) {
3324 u = javastring_toutf(obj, false);
3325 utf_display_printable_ascii(u);
3329 else if (type == TYPE_INT) {
3330 printf(" %ld", (long) value.i);
3332 else if (type == TYPE_LNG) {
3333 printf(" %lld", (long long) value.l);
3335 else if (type == TYPE_FLT) {
3336 printf(" %f", value.f);
3338 else if (type == TYPE_DBL) {
3339 printf(" %f", value.d);
3342 #endif /* !defined(NDEBUG) */
3345 #if !defined(NDEBUG)
3346 void replace_source_frame_println(sourceframe_t *frame)
3351 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3352 printf("\tNATIVE\n");
3353 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3354 printf("\tnativepc: %p\n", frame->nativepc);
3355 printf("\tframesize: %d\n", frame->nativeframesize);
3358 for (i=0; i<INT_REG_CNT; ++i) {
3359 if (nregdescint[i] == REG_SAV)
3360 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3364 for (i=0; i<FLT_REG_CNT; ++i) {
3365 if (nregdescfloat[i] == REG_SAV)
3366 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3374 method_println(frame->method);
3375 printf("\tid: %d\n", frame->id);
3376 printf("\ttype: %s\n", replace_type_str[frame->type]);
3379 if (frame->instance.a) {
3380 printf("\tinstance: ");
3381 java_value_print(TYPE_ADR, frame->instance);
3385 if (frame->javalocalcount) {
3386 printf("\tlocals (%d):\n",frame->javalocalcount);
3387 for (i=0; i<frame->javalocalcount; ++i) {
3388 t = frame->javalocaltype[i];
3389 if (t == TYPE_VOID) {
3390 printf("\tlocal[ %2d] = void\n",i);
3393 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3394 java_value_print(t, frame->javalocals[i]);
3401 if (frame->javastackdepth) {
3402 printf("\tstack (depth %d):\n",frame->javastackdepth);
3403 for (i=0; i<frame->javastackdepth; ++i) {
3404 t = frame->javastacktype[i];
3405 if (t == TYPE_VOID) {
3406 printf("\tstack[%2d] = void", i);
3409 printf("\tstack[%2d] = ",i);
3410 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3417 if (frame->syncslotcount) {
3418 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3419 for (i=0; i<frame->syncslotcount; ++i) {
3420 printf("\tslot[%2d] = %016llx\n",i,(unsigned long long) frame->syncslots[i].p);
3425 if (frame->fromcode) {
3426 printf("\tfrom %p ", (void*)frame->fromcode);
3427 method_println(frame->fromcode->m);
3429 if (frame->tocode) {
3430 printf("\tto %p ", (void*)frame->tocode);
3431 method_println(frame->tocode->m);
3434 if (frame->fromrp) {
3435 printf("\tfrom replacement point:\n");
3436 replace_replacement_point_println(frame->fromrp, 2);
3439 printf("\tto replacement point:\n");
3440 replace_replacement_point_println(frame->torp, 2);
3445 #endif /* !defined(NDEBUG) */
3448 /* replace_sourcestate_println *************************************************
3453 ss...............the source state to print
3455 *******************************************************************************/
3457 #if !defined(NDEBUG)
3458 void replace_sourcestate_println(sourcestate_t *ss)
3461 sourceframe_t *frame;
3464 printf("(sourcestate_t *)NULL\n");
3468 printf("sourcestate_t:\n");
3470 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3471 printf(" frame %d:\n", i);
3472 replace_source_frame_println(frame);
3478 /* replace_sourcestate_println_short *******************************************
3480 Print a compact representation of the given source state.
3483 ss...............the source state to print
3485 *******************************************************************************/
3487 #if !defined(NDEBUG)
3488 void replace_sourcestate_println_short(sourcestate_t *ss)
3490 sourceframe_t *frame;
3492 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3495 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3496 printf("NATIVE (pc %p size %d) ",
3497 (void*)frame->nativepc, frame->nativeframesize);
3498 replace_stackframeinfo_println(frame->sfi);
3503 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3506 printf("%s", replace_type_str[frame->fromrp->type]);
3508 if (frame->torp && frame->torp->type != frame->fromrp->type)
3509 printf("->%s", replace_type_str[frame->torp->type]);
3511 if (frame->tocode != frame->fromcode)
3512 printf(" (%p->%p/%d) ",
3513 (void*) frame->fromcode, (void*) frame->tocode,
3516 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3518 method_println(frame->method);
3523 #if !defined(NDEBUG)
3524 static void replace_stackframeinfo_println(stackframeinfo_t *sfi)
3526 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3527 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3528 (void*)sfi->ra, (void*)sfi->xpc);
3531 method_println(sfi->code->m);
3539 * These are local overrides for various environment variables in Emacs.
3540 * Please do not remove this and leave it at the end of the file, where
3541 * Emacs will automagically detect them.
3542 * ---------------------------------------------------------------------
3545 * indent-tabs-mode: t
3549 * vim:noexpandtab:sw=4:ts=4: