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>
75 /*** configuration of native stack slot size **********************************/
77 /* XXX this should be in md-abi.h files, probably */
79 #define SIZE_OF_STACKSLOT 8
80 #define STACK_SLOTS_PER_FLOAT 1
81 typedef u8 stackslot_t;
84 /*** debugging ****************************************************************/
87 static void java_value_print(s4 type, replace_val_t value);
88 static void replace_stackframeinfo_println(stackframeinfo_t *sfi);
92 #define DOLOG(code) do{ if (opt_TraceReplacement > 1) { code; } } while(0)
93 #define DOLOG_SHORT(code) do{ if (opt_TraceReplacement > 0) { code; } } while(0)
96 #define DOLOG_SHORT(code)
100 /*** statistics ***************************************************************/
102 #define REPLACE_STATISTICS
104 #if defined(REPLACE_STATISTICS)
106 static int stat_replacements = 0;
107 static int stat_frames = 0;
108 static int stat_recompile = 0;
109 static int stat_staticpatch = 0;
110 static int stat_unroll_inline = 0;
111 static int stat_unroll_call = 0;
112 static int stat_dist_frames[20] = { 0 };
113 static int stat_dist_locals[20] = { 0 };
114 static int stat_dist_locals_adr[10] = { 0 };
115 static int stat_dist_locals_prim[10] = { 0 };
116 static int stat_dist_locals_ret[10] = { 0 };
117 static int stat_dist_locals_void[10] = { 0 };
118 static int stat_dist_stack[10] = { 0 };
119 static int stat_dist_stack_adr[10] = { 0 };
120 static int stat_dist_stack_prim[10] = { 0 };
121 static int stat_dist_stack_ret[10] = { 0 };
122 static int stat_methods = 0;
123 static int stat_rploints = 0;
124 static int stat_regallocs = 0;
125 static int stat_dist_method_rplpoints[20] = { 0 };
127 #define REPLACE_COUNT(cnt) (cnt)++
128 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
129 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
131 #define REPLACE_COUNT_DIST(array, val) \
133 int limit = (sizeof(array) / sizeof(int)) - 1; \
134 if ((val) < (limit)) (array)[val]++; \
135 else (array)[limit]++; \
138 static void replace_statistics_source_frame(sourceframe_t *frame);
142 #define REPLACE_COUNT(cnt)
143 #define REPLACE_COUNT_IF(cnt, cond)
144 #define REPLACE_COUNT_INC(cnt, inc)
145 #define REPLACE_COUNT_DIST(array, val)
147 #endif /* defined(REPLACE_STATISTICS) */
150 /*** constants used internally ************************************************/
152 #define TOP_IS_NORMAL 0
153 #define TOP_IS_ON_STACK 1
154 #define TOP_IS_IN_ITMP1 2
155 #define TOP_IS_VOID 3
158 /******************************************************************************/
159 /* PART I: Creating / freeing replacement points */
160 /******************************************************************************/
163 /* replace_create_replacement_point ********************************************
165 Create a replacement point.
168 jd...............current jitdata
169 iinfo............inlining info for the current position
170 rp...............pre-allocated (uninitialized) rplpoint
171 type.............RPLPOINT_TYPE constant
172 iptr.............current instruction
173 *pra.............current rplalloc pointer
174 javalocals.......the javalocals at the current point
175 stackvars........the stack variables at the current point
176 stackdepth.......the stack depth at the current point
177 paramcount.......number of parameters at the start of stackvars
180 *rpa.............points to the next free rplalloc
182 *******************************************************************************/
184 static void replace_create_replacement_point(jitdata *jd,
185 insinfo_inline *iinfo,
202 REPLACE_COUNT(stat_rploints);
204 rp->method = (iinfo) ? iinfo->method : jd->m;
205 rp->pc = NULL; /* set by codegen */
206 rp->callsize = 0; /* set by codegen */
210 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
212 /* XXX unify these two fields */
213 rp->parent = (iinfo) ? iinfo->rp : NULL;
215 /* store local allocation info of javalocals */
218 for (i = 0; i < rp->method->maxlocals; ++i) {
219 index = javalocals[i];
226 ra->flags = v->flags & (INMEMORY);
227 ra->regoff = v->vv.regoff;
231 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
239 /* store allocation info of java stack vars */
241 for (i = 0; i < stackdepth; ++i) {
242 v = VAR(stackvars[i]);
243 ra->flags = v->flags & (INMEMORY);
244 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
246 /* XXX how to handle locals on the stack containing returnAddresses? */
247 if (v->type == TYPE_RET) {
248 assert(stackvars[i] >= jd->localcount);
249 ra->regoff = v->vv.retaddr->nr;
252 ra->regoff = v->vv.regoff;
256 /* total number of allocations */
258 rp->regalloccount = ra - rp->regalloc;
264 /* replace_create_inline_start_replacement_point *******************************
266 Create an INLINE_START replacement point.
269 jd...............current jitdata
270 rp...............pre-allocated (uninitialized) rplpoint
271 iptr.............current instruction
272 *pra.............current rplalloc pointer
273 javalocals.......the javalocals at the current point
276 *rpa.............points to the next free rplalloc
279 the insinfo_inline * for the following inlined body
281 *******************************************************************************/
283 static insinfo_inline * replace_create_inline_start_replacement_point(
290 insinfo_inline *calleeinfo;
293 calleeinfo = iptr->sx.s23.s3.inlineinfo;
297 replace_create_replacement_point(jd, calleeinfo->parent, rp,
298 RPLPOINT_TYPE_INLINE, iptr, pra,
300 calleeinfo->stackvars, calleeinfo->stackvarscount,
301 calleeinfo->paramcount);
303 if (calleeinfo->synclocal != UNUSED) {
305 ra->index = RPLALLOC_SYNC;
306 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
307 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
317 /* replace_create_replacement_points *******************************************
319 Create the replacement points for the given code.
322 jd...............current jitdata, must not have any replacement points
325 code->rplpoints.......set to the list of replacement points
326 code->rplpointcount...number of replacement points
327 code->regalloc........list of allocation info
328 code->regalloccount...total length of allocation info list
329 code->globalcount.....number of global allocations at the
330 start of code->regalloc
333 true.............everything ok
334 false............an exception has been thrown
336 *******************************************************************************/
338 #define CLEAR_javalocals(array, method) \
340 for (i=0; i<(method)->maxlocals; ++i) \
341 (array)[i] = UNUSED; \
344 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
346 if ((array) != NULL) \
347 MCOPY((dest), (array), s4, (method)->maxlocals); \
349 CLEAR_javalocals((dest), (method)); \
352 #define COUNT_javalocals(array, method, counter) \
354 for (i=0; i<(method)->maxlocals; ++i) \
355 if ((array)[i] != UNUSED) \
359 bool replace_create_replacement_points(jitdata *jd)
377 insinfo_inline *iinfo;
380 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
384 REPLACE_COUNT(stat_methods);
386 /* get required compiler data */
391 /* assert that we wont overwrite already allocated data */
395 assert(code->rplpoints == NULL);
396 assert(code->rplpointcount == 0);
397 assert(code->regalloc == NULL);
398 assert(code->regalloccount == 0);
399 assert(code->globalcount == 0);
403 /* in instance methods, we may need a rplpoint at the method entry */
405 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
406 if (!(m->flags & ACC_STATIC)) {
407 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
413 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
415 /* iterate over the basic block list to find replacement points */
420 javalocals = (s4*) DumpMemory::allocate(sizeof(s4) * jd->maxlocals);
422 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
426 if (bptr->flags < BBFINISHED)
429 /* get info about this block */
432 iinfo = bptr->inlineinfo;
434 /* initialize javalocals at the start of this block */
436 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
438 /* iterate over the instructions */
441 iend = iptr + bptr->icount;
445 for (; iptr != iend; ++iptr) {
447 #if defined(ENABLE_GC_CACAO)
449 md = iptr->sx.s23.s3.bte->md;
451 COUNT_javalocals(javalocals, m, alloccount);
452 alloccount += iptr->s1.argcount;
454 alloccount -= iinfo->throughcount;
458 case ICMD_INVOKESTATIC:
459 case ICMD_INVOKESPECIAL:
460 case ICMD_INVOKEVIRTUAL:
461 case ICMD_INVOKEINTERFACE:
462 INSTRUCTION_GET_METHODDESC(iptr, md);
464 COUNT_javalocals(javalocals, m, alloccount);
465 alloccount += iptr->s1.argcount;
467 alloccount -= iinfo->throughcount;
475 stack_javalocals_store(iptr, javalocals);
489 case ICMD_INLINE_START:
490 iinfo = iptr->sx.s23.s3.inlineinfo;
493 COUNT_javalocals(javalocals, m, alloccount);
494 alloccount += iinfo->stackvarscount;
495 if (iinfo->synclocal != UNUSED)
499 /* javalocals may be set at next block start, or now */
500 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
503 case ICMD_INLINE_BODY:
504 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
506 jl = iinfo->javalocals_start;
508 /* get the javalocals from the following block start */
510 jl = bptr->next->javalocals;
513 COUNT_javalocals(jl, m, alloccount);
516 case ICMD_INLINE_END:
517 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
518 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
519 iinfo = iptr->sx.s23.s3.inlineinfo;
521 if (iinfo->javalocals_end)
522 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
523 iinfo = iinfo->parent;
527 if (iptr == bptr->iinstr)
529 } /* end instruction loop */
531 /* create replacement points at targets of backward branches */
532 /* We only need the replacement point there, if there is no */
533 /* replacement point inside the block. */
535 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
536 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
537 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
541 if (test > startcount) {
542 /* we don't need an extra rplpoint */
543 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
547 alloccount += bptr->indepth;
548 if (bptr->inlineinfo)
549 alloccount -= bptr->inlineinfo->throughcount;
551 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
555 } /* end basicblock loop */
557 /* if no points were found, there's nothing to do */
562 /* allocate replacement point array and allocation array */
564 rplpoints = MNEW(rplpoint, count);
565 regalloc = MNEW(rplalloc, alloccount);
568 /* initialize replacement point structs */
572 /* XXX try to share code with the counting loop! */
574 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
577 if (bptr->flags < BBFINISHED)
580 /* get info about this block */
583 iinfo = bptr->inlineinfo;
585 /* initialize javalocals at the start of this block */
587 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
589 /* create replacement points at targets of backward branches */
591 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
593 i = (iinfo) ? iinfo->throughcount : 0;
594 replace_create_replacement_point(jd, iinfo, rp++,
595 bptr->type, bptr->iinstr, &ra,
596 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
598 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
599 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
602 /* iterate over the instructions */
605 iend = iptr + bptr->icount;
607 for (; iptr != iend; ++iptr) {
609 #if defined(ENABLE_GC_CACAO)
611 md = iptr->sx.s23.s3.bte->md;
613 i = (iinfo) ? iinfo->throughcount : 0;
614 replace_create_replacement_point(jd, iinfo, rp++,
615 RPLPOINT_TYPE_CALL, iptr, &ra,
616 javalocals, iptr->sx.s23.s2.args,
617 iptr->s1.argcount - i,
622 case ICMD_INVOKESTATIC:
623 case ICMD_INVOKESPECIAL:
624 case ICMD_INVOKEVIRTUAL:
625 case ICMD_INVOKEINTERFACE:
626 INSTRUCTION_GET_METHODDESC(iptr, md);
628 i = (iinfo) ? iinfo->throughcount : 0;
629 replace_create_replacement_point(jd, iinfo, rp++,
630 RPLPOINT_TYPE_CALL, iptr, &ra,
631 javalocals, iptr->sx.s23.s2.args,
632 iptr->s1.argcount - i,
641 stack_javalocals_store(iptr, javalocals);
649 replace_create_replacement_point(jd, iinfo, rp++,
650 RPLPOINT_TYPE_RETURN, iptr, &ra,
651 NULL, &(iptr->s1.varindex), 1, 0);
655 replace_create_replacement_point(jd, iinfo, rp++,
656 RPLPOINT_TYPE_RETURN, iptr, &ra,
660 case ICMD_INLINE_START:
661 iinfo = replace_create_inline_start_replacement_point(
662 jd, rp++, iptr, &ra, javalocals);
664 /* javalocals may be set at next block start, or now */
665 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
668 case ICMD_INLINE_BODY:
669 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
671 jl = iinfo->javalocals_start;
673 /* get the javalocals from the following block start */
675 jl = bptr->next->javalocals;
677 /* create a non-trappable rplpoint */
678 replace_create_replacement_point(jd, iinfo, rp++,
679 RPLPOINT_TYPE_BODY, iptr, &ra,
681 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
684 case ICMD_INLINE_END:
685 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
686 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
687 iinfo = iptr->sx.s23.s3.inlineinfo;
689 if (iinfo->javalocals_end)
690 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
691 iinfo = iinfo->parent;
694 } /* end instruction loop */
695 } /* end basicblock loop */
697 assert((rp - rplpoints) == count);
698 assert((ra - regalloc) == alloccount);
700 /* store the data in the codeinfo */
702 code->rplpoints = rplpoints;
703 code->rplpointcount = count;
704 code->regalloc = regalloc;
705 code->regalloccount = alloccount;
706 code->globalcount = 0;
707 code->memuse = rd->memuse;
709 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
710 REPLACE_COUNT_INC(stat_regallocs, alloccount);
712 /* everything alright */
718 /* replace_free_replacement_points *********************************************
720 Free memory used by replacement points.
723 code.............codeinfo whose replacement points should be freed.
725 *******************************************************************************/
727 void replace_free_replacement_points(codeinfo *code)
732 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
735 MFREE(code->regalloc,rplalloc,code->regalloccount);
737 code->rplpoints = NULL;
738 code->rplpointcount = 0;
739 code->regalloc = NULL;
740 code->regalloccount = 0;
741 code->globalcount = 0;
745 /******************************************************************************/
746 /* PART II: Activating / deactivating replacement points */
747 /******************************************************************************/
750 /* replace_activate_replacement_points *****************************************
752 Activate the replacement points of the given compilation unit. When this
753 function returns, the replacement points are "armed", so each thread
754 reaching one of the points will enter the replacement mechanism.
757 code.............codeinfo of which replacement points should be
759 mappable.........if true, only mappable replacement points are
762 *******************************************************************************/
764 void replace_activate_replacement_points(codeinfo *code, bool mappable)
771 assert(code->savedmcode == NULL);
773 /* count trappable replacement points */
776 i = code->rplpointcount;
777 rp = code->rplpoints;
779 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
782 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
788 /* allocate buffer for saved machine code */
790 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
791 code->savedmcode = savedmcode;
792 savedmcode += count * REPLACEMENT_PATCH_SIZE;
794 /* activate trappable replacement points */
795 /* (in reverse order to handle overlapping points within basic blocks) */
797 i = code->rplpointcount;
798 rp = code->rplpoints + i;
800 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
802 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
805 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
808 DOLOG( printf("activate replacement point:\n");
809 replace_replacement_point_println(rp, 1); fflush(stdout); );
811 savedmcode -= REPLACEMENT_PATCH_SIZE;
813 #if defined(ENABLE_JIT)
814 # if defined(ENABLE_DISASSEMBLER)
815 DOLOG( printf("\tinstruction before: ");
816 disassinstr(rp->pc); fflush(stdout); );
819 md_patch_replacement_point(rp->pc, savedmcode, false);
821 # if defined(ENABLE_DISASSEMBLER)
822 DOLOG( printf("\tinstruction after : ");
823 disassinstr(rp->pc); fflush(stdout); );
827 rp->flags |= RPLPOINT_FLAG_ACTIVE;
830 assert(savedmcode == code->savedmcode);
834 /* replace_deactivate_replacement_points ***************************************
836 Deactivate a replacement points in the given compilation unit.
837 When this function returns, the replacement points will be "un-armed",
838 that is a each thread reaching a point will just continue normally.
841 code.............the compilation unit
843 *******************************************************************************/
845 void replace_deactivate_replacement_points(codeinfo *code)
852 if (code->savedmcode == NULL) {
853 /* disarm countdown points by patching the branches */
855 i = code->rplpointcount;
856 rp = code->rplpoints;
858 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
859 == RPLPOINT_FLAG_COUNTDOWN)
862 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
869 assert(code->savedmcode != NULL);
870 savedmcode = code->savedmcode;
872 /* de-activate each trappable replacement point */
874 i = code->rplpointcount;
875 rp = code->rplpoints;
878 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
883 DOLOG( printf("deactivate replacement point:\n");
884 replace_replacement_point_println(rp, 1); fflush(stdout); );
886 #if defined(ENABLE_JIT)
887 # if defined(ENABLE_DISASSEMBLER)
888 DOLOG( printf("\tinstruction before: ");
889 disassinstr(rp->pc); fflush(stdout); );
892 md_patch_replacement_point(rp->pc, savedmcode, true);
894 # if defined(ENABLE_DISASSEMBLER)
895 DOLOG( printf("\tinstruction before: ");
896 disassinstr(rp->pc); fflush(stdout); );
900 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
902 savedmcode += REPLACEMENT_PATCH_SIZE;
905 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
907 /* free saved machine code */
909 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
910 code->savedmcode = NULL;
914 /******************************************************************************/
915 /* PART III: The replacement mechanism */
916 /******************************************************************************/
919 /* replace_read_value **********************************************************
921 Read a value with the given allocation from the execution state.
924 es...............execution state
925 ra...............allocation
926 javaval..........where to put the value
929 *javaval.........the value
931 *******************************************************************************/
933 static void replace_read_value(executionstate_t *es,
935 replace_val_t *javaval)
937 if (ra->flags & INMEMORY) {
938 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
939 #ifdef HAS_4BYTE_STACKSLOT
940 if (IS_2_WORD_TYPE(ra->type)) {
941 javaval->l = *(u8*)(es->sp + ra->regoff);
945 javaval->p = *(ptrint*)(es->sp + ra->regoff);
946 #ifdef HAS_4BYTE_STACKSLOT
951 /* allocated register */
952 if (IS_FLT_DBL_TYPE(ra->type)) {
953 javaval->d = es->fltregs[ra->regoff];
955 if (ra->type == TYPE_FLT)
956 javaval->f = javaval->d;
958 #if defined(HAS_ADDRESS_REGISTER_FILE)
959 else if (IS_ADR_TYPE(ra->type)) {
960 javaval->p = es->adrregs[ra->regoff];
964 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
965 if (ra->type == TYPE_LNG) {
966 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
967 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
970 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
971 javaval->p = es->intregs[ra->regoff];
977 /* replace_write_value *********************************************************
979 Write a value to the given allocation in the execution state.
982 es...............execution state
983 ra...............allocation
984 *javaval.........the value
986 *******************************************************************************/
988 static void replace_write_value(executionstate_t *es,
990 replace_val_t *javaval)
992 if (ra->flags & INMEMORY) {
993 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
994 #ifdef HAS_4BYTE_STACKSLOT
995 if (IS_2_WORD_TYPE(ra->type)) {
996 *(u8*)(es->sp + ra->regoff) = javaval->l;
1000 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1001 #ifdef HAS_4BYTE_STACKSLOT
1006 /* allocated register */
1009 es->fltregs[ra->regoff] = (double) javaval->f;
1012 es->fltregs[ra->regoff] = javaval->d;
1014 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1016 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1017 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1020 #if defined(HAS_ADDRESS_REGISTER_FILE)
1022 es->adrregs[ra->regoff] = javaval->p;
1025 es->intregs[ra->regoff] = javaval->p;
1031 /* replace_new_sourceframe *****************************************************
1033 Allocate a new source frame and insert it at the front of the frame list.
1036 ss...............the source state
1039 ss->frames.......set to new frame (the new head of the frame list).
1042 returns the new frame
1044 *******************************************************************************/
1046 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1048 sourceframe_t *frame;
1050 frame = (sourceframe_t*) DumpMemory::allocate(sizeof(sourceframe_t));
1051 MZERO(frame, sourceframe_t, 1);
1053 frame->down = ss->frames;
1060 /* replace_read_executionstate *************************************************
1062 Read a source frame from the given executions state.
1063 The new source frame is pushed to the front of the frame list of the
1067 rp...............replacement point at which `es` was taken
1068 es...............execution state
1069 ss...............the source state to add the source frame to
1070 topframe.........true, if the first (top-most) source frame on the
1074 *ss..............the source state with the newly created source frame
1077 *******************************************************************************/
1079 static s4 replace_normalize_type_map[] = {
1080 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1081 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1082 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1083 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1084 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1085 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1086 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1090 static void replace_read_executionstate(rplpoint *rp,
1091 executionstate_t *es,
1100 sourceframe_t *frame;
1103 stackslot_t *basesp;
1105 code = code_find_codeinfo_for_pc(rp->pc);
1107 topslot = TOP_IS_NORMAL;
1111 sp = (stackslot_t *) es->sp;
1113 /* in some cases the top stack slot is passed in REG_ITMP1 */
1115 if (rp->type == BBTYPE_EXH) {
1116 topslot = TOP_IS_IN_ITMP1;
1119 /* calculate base stack pointer */
1121 basesp = sp + code->stackframesize;
1123 /* create the source frame */
1125 frame = replace_new_sourceframe(ss);
1126 frame->method = rp->method;
1128 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1129 frame->type = replace_normalize_type_map[rp->type];
1131 frame->fromcode = code;
1133 /* read local variables */
1135 count = m->maxlocals;
1136 frame->javalocalcount = count;
1137 frame->javalocals = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1138 frame->javalocaltype = (u1*) DumpMemory::allocate(sizeof(u1) * count);
1140 /* mark values as undefined */
1141 for (i=0; i<count; ++i) {
1142 #if !defined(NDEBUG)
1143 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1145 frame->javalocaltype[i] = TYPE_VOID;
1148 /* some entries in the intregs array are not meaningful */
1149 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1150 #if !defined(NDEBUG)
1151 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1153 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1155 #endif /* !defined(NDEBUG) */
1157 /* read javalocals */
1159 count = rp->regalloccount;
1162 while (count && (i = ra->index) >= 0) {
1163 assert(i < m->maxlocals);
1164 frame->javalocaltype[i] = ra->type;
1165 if (ra->type == TYPE_RET)
1166 frame->javalocals[i].i = ra->regoff;
1168 replace_read_value(es, ra, frame->javalocals + i);
1173 /* read instance, if this is the first rplpoint */
1175 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1176 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1178 /* we are at the start of the method body, so if local 0 is set, */
1179 /* it is the instance. */
1180 if (frame->javalocaltype[0] == TYPE_ADR)
1181 frame->instance = frame->javalocals[0];
1186 md = rp->method->parseddesc;
1188 assert(md->paramcount >= 1);
1189 instra.type = TYPE_ADR;
1190 instra.regoff = md->params[0].regoff;
1191 if (md->params[0].inmemory) {
1192 instra.flags = INMEMORY;
1193 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1198 replace_read_value(es, &instra, &(frame->instance));
1201 #if defined(__I386__)
1202 else if (!(rp->method->flags & ACC_STATIC)) {
1203 /* On i386 we always pass the first argument on stack. */
1204 frame->instance.a = *(java_object_t **)(basesp + 1);
1207 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1209 /* read stack slots */
1211 frame->javastackdepth = count;
1212 frame->javastack = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1213 frame->javastacktype = (u1*) DumpMemory::allocate(sizeof(u1) * count);
1215 #if !defined(NDEBUG)
1216 /* mark values as undefined */
1217 for (i=0; i<count; ++i) {
1218 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1219 frame->javastacktype[i] = TYPE_VOID;
1221 #endif /* !defined(NDEBUG) */
1225 /* the first stack slot is special in SBR and EXH blocks */
1227 if (topslot == TOP_IS_ON_STACK) {
1230 assert(ra->index == RPLALLOC_STACK);
1231 assert(ra->type == TYPE_ADR);
1232 frame->javastack[i].p = sp[-1];
1233 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1238 else if (topslot == TOP_IS_IN_ITMP1) {
1241 assert(ra->index == RPLALLOC_STACK);
1242 assert(ra->type == TYPE_ADR);
1243 frame->javastack[i].p = es->intregs[REG_ITMP1];
1244 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1249 else if (topslot == TOP_IS_VOID) {
1252 assert(ra->index == RPLALLOC_STACK);
1253 frame->javastack[i].l = 0;
1254 frame->javastacktype[i] = TYPE_VOID;
1260 /* read remaining stack slots */
1262 for (; count--; ra++) {
1263 if (ra->index == RPLALLOC_SYNC) {
1264 assert(rp->type == RPLPOINT_TYPE_INLINE);
1266 /* only read synchronization slots when traversing an inline point */
1269 sourceframe_t *calleeframe = frame->down;
1270 assert(calleeframe);
1271 assert(calleeframe->syncslotcount == 0);
1272 assert(calleeframe->syncslots == NULL);
1274 calleeframe->syncslotcount = 1;
1275 calleeframe->syncslots = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t));
1276 replace_read_value(es,ra,calleeframe->syncslots);
1279 frame->javastackdepth--;
1283 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1285 /* do not read parameters of calls down the call chain */
1287 if (!topframe && ra->index == RPLALLOC_PARAM) {
1288 frame->javastackdepth--;
1291 if (ra->type == TYPE_RET)
1292 frame->javastack[i].i = ra->regoff;
1294 replace_read_value(es,ra,frame->javastack + i);
1295 frame->javastacktype[i] = ra->type;
1302 /* replace_write_executionstate ************************************************
1304 Pop a source frame from the front of the frame list of the given source state
1305 and write its values into the execution state.
1308 rp...............replacement point for which execution state should be
1310 es...............the execution state to modify
1311 ss...............the given source state
1312 topframe.........true, if this is the last (top-most) source frame to be
1316 *es..............the execution state derived from the source state
1318 *******************************************************************************/
1320 static void replace_write_executionstate(rplpoint *rp,
1321 executionstate_t *es,
1330 sourceframe_t *frame;
1333 stackslot_t *basesp;
1335 code = code_find_codeinfo_for_pc(rp->pc);
1337 topslot = TOP_IS_NORMAL;
1339 /* pop a source frame */
1343 ss->frames = frame->down;
1345 /* calculate stack pointer */
1347 sp = (stackslot_t *) es->sp;
1349 basesp = sp + code->stackframesize;
1351 /* in some cases the top stack slot is passed in REG_ITMP1 */
1353 if (rp->type == BBTYPE_EXH) {
1354 topslot = TOP_IS_IN_ITMP1;
1357 /* write javalocals */
1360 count = rp->regalloccount;
1362 while (count && (i = ra->index) >= 0) {
1363 assert(i < m->maxlocals);
1364 assert(i < frame->javalocalcount);
1365 assert(ra->type == frame->javalocaltype[i]);
1366 if (ra->type == TYPE_RET) {
1367 /* XXX assert that it matches this rplpoint */
1370 replace_write_value(es, ra, frame->javalocals + i);
1375 /* write stack slots */
1379 /* the first stack slot is special in SBR and EXH blocks */
1381 if (topslot == TOP_IS_ON_STACK) {
1384 assert(ra->index == RPLALLOC_STACK);
1385 assert(i < frame->javastackdepth);
1386 assert(frame->javastacktype[i] == TYPE_ADR);
1387 sp[-1] = frame->javastack[i].p;
1392 else if (topslot == TOP_IS_IN_ITMP1) {
1395 assert(ra->index == RPLALLOC_STACK);
1396 assert(i < frame->javastackdepth);
1397 assert(frame->javastacktype[i] == TYPE_ADR);
1398 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1403 else if (topslot == TOP_IS_VOID) {
1406 assert(ra->index == RPLALLOC_STACK);
1407 assert(i < frame->javastackdepth);
1408 assert(frame->javastacktype[i] == TYPE_VOID);
1414 /* write remaining stack slots */
1416 for (; count--; ra++) {
1417 if (ra->index == RPLALLOC_SYNC) {
1418 assert(rp->type == RPLPOINT_TYPE_INLINE);
1420 /* only write synchronization slots when traversing an inline point */
1423 assert(frame->down);
1424 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1425 assert(frame->down->syncslots != NULL);
1427 replace_write_value(es,ra,frame->down->syncslots);
1432 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1434 /* do not write parameters of calls down the call chain */
1436 if (!topframe && ra->index == RPLALLOC_PARAM) {
1439 ra->index = RPLALLOC_PARAM;
1442 replace_write_value(es,ra,&v);
1446 assert(i < frame->javastackdepth);
1447 assert(ra->type == frame->javastacktype[i]);
1448 if (ra->type == TYPE_RET) {
1449 /* XXX assert that it matches this rplpoint */
1452 replace_write_value(es,ra,frame->javastack + i);
1464 /* md_pop_stackframe ***********************************************************
1466 Restore callee-saved registers (including the RA register),
1467 set the stack pointer to the next stackframe,
1468 set the PC to the return address of the popped frame.
1470 *** This function imitates the effects of the method epilog ***
1471 *** and returning from the method call. ***
1474 es...............execution state
1477 *es..............the execution state after popping the stack frame
1478 NOTE: es->code and es->pv are NOT updated.
1480 *******************************************************************************/
1482 void md_pop_stackframe(executionstate_t *es)
1488 stackslot_t *basesp;
1493 /* calculate the size of the stackframe */
1495 framesize = md_stacktrace_get_framesize(es->code);
1497 /* read the return address */
1499 #if STACKFRAME_LEAFMETHODS_RA_REGISTER
1500 if (code_is_leafmethod(es->code))
1504 ra = (u1*) md_stacktrace_get_returnaddress(es->sp, framesize);
1506 /* calculate the base of the stack frame */
1508 sp = (stackslot_t *) es->sp;
1509 basesp = sp + es->code->stackframesize;
1511 /* restore return address, if part of frame */
1513 #if STACKFRAME_RA_TOP_OF_FRAME
1514 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
1515 if (!code_is_leafmethod(es->code))
1517 es->ra = (u1*) (ptrint) *--basesp;
1518 #endif /* STACKFRAME_RA_TOP_OF_FRAME */
1520 #if STACKFRAME_RA_LINKAGE_AREA
1521 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
1522 if (!code_is_leafmethod(es->code))
1524 es->ra = *((uint8_t**) ((intptr_t) basesp + LA_LR_OFFSET));
1525 #endif /* STACKFRAME_RA_LINKAGE_AREA */
1527 /* restore saved int registers */
1530 for (i=0; i<es->code->savedintcount; ++i) {
1531 while (nregdescint[--reg] != REG_SAV)
1534 es->intregs[reg] = *((uintptr_t*) basesp);
1537 /* restore saved flt registers */
1541 for (i=0; i<es->code->savedfltcount; ++i) {
1542 while (nregdescfloat[--reg] != REG_SAV)
1544 basesp -= STACK_SLOTS_PER_FLOAT;
1545 es->fltregs[reg] = *((double*) basesp);
1548 #if defined(HAS_ADDRESS_REGISTER_FILE)
1549 /* restore saved adr registers */
1552 for (i=0; i<es->code->savedadrcount; ++i) {
1553 while (nregdescadr[--reg] != REG_SAV)
1556 es->adrregs[reg] = *((uintptr_t*) basesp);
1560 /* adjust the stackpointer */
1562 es->sp += framesize;
1563 #if STACKFRMAE_RA_BETWEEN_FRAMES
1564 es->sp += SIZEOF_VOID_P; /* skip return address */
1567 /* set the program counter to the return address */
1571 /* in debugging mode clobber non-saved registers */
1573 #if !defined(NDEBUG)
1575 for (i=0; i<INT_REG_CNT; ++i)
1576 if (nregdescint[i] != REG_SAV)
1577 es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1578 for (i=0; i<FLT_REG_CNT; ++i)
1579 if (nregdescfloat[i] != REG_SAV)
1580 *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1581 # if defined(HAS_ADDRESS_REGISTER_FILE)
1582 for (i=0; i<ADR_REG_CNT; ++i)
1583 if (nregdescadr[i] != REG_SAV)
1584 es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1586 #endif /* !defined(NDEBUG) */
1590 /* md_push_stackframe **********************************************************
1592 Save the given return address, build the new stackframe,
1593 and store callee-saved registers.
1595 *** This function imitates the effects of a call and the ***
1596 *** method prolog of the callee. ***
1599 es...............execution state
1600 calleecode.......the code we are "calling"
1601 ra...............the return address to save
1604 *es..............the execution state after pushing the stack frame
1605 NOTE: es->pc, es->code, and es->pv are NOT updated.
1607 *******************************************************************************/
1609 void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra)
1613 stackslot_t *basesp;
1619 /* write the return address */
1621 #if STACKFRMAE_RA_BETWEEN_FRAMES
1622 es->sp -= SIZEOF_VOID_P;
1623 *((void **)es->sp) = (void *) ra;
1624 if (calleecode->stackframesize)
1625 es->sp -= (SIZE_OF_STACKSLOT - SIZEOF_VOID_P);
1626 #endif /* STACKFRAME_RA_BETWEEN_FRAMES */
1628 es->ra = (u1*) (ptrint) ra;
1630 /* build the stackframe */
1632 DOLOG( printf("building stackframe of %d words at %p\n",
1633 calleecode->stackframesize, (void*)es->sp); );
1635 sp = (stackslot_t *) es->sp;
1638 sp -= calleecode->stackframesize;
1641 /* in debug mode, invalidate stack frame first */
1643 /* XXX may not invalidate linkage area used by native code! */
1645 #if !defined(NDEBUG) && 0
1646 for (i=0; i< (basesp - sp) && i < 1; ++i) {
1647 sp[i] = 0xdeaddeadU;
1651 #if defined(__I386__)
1652 /* Stackslot 0 may contain the object instance for vftbl patching.
1653 Destroy it, so there's no undefined value used. */
1654 if ((basesp - sp) > 0) {
1659 /* save the return address register */
1661 #if STACKFRAME_RA_TOP_OF_FRAME
1662 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
1663 if (!code_is_leafmethod(calleecode))
1665 *--basesp = (ptrint) ra;
1666 #endif /* STACKFRAME_RA_TOP_OF_FRAME */
1668 #if STACKFRAME_RA_LINKAGE_AREA
1669 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
1670 if (!code_is_leafmethod(calleecode))
1672 *((uint8_t**) ((intptr_t) basesp + LA_LR_OFFSET)) = ra;
1673 #endif /* STACKFRAME_RA_LINKAGE_AREA */
1675 /* save int registers */
1678 for (i=0; i<calleecode->savedintcount; ++i) {
1679 while (nregdescint[--reg] != REG_SAV)
1682 *((uintptr_t*) basesp) = es->intregs[reg];
1684 /* XXX may not clobber saved regs used by native code! */
1685 #if !defined(NDEBUG) && 0
1686 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1690 /* save flt registers */
1694 for (i=0; i<calleecode->savedfltcount; ++i) {
1695 while (nregdescfloat[--reg] != REG_SAV)
1697 basesp -= STACK_SLOTS_PER_FLOAT;
1698 *((double*) basesp) = es->fltregs[reg];
1700 /* XXX may not clobber saved regs used by native code! */
1701 #if !defined(NDEBUG) && 0
1702 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1706 #if defined(HAS_ADDRESS_REGISTER_FILE)
1707 /* save adr registers */
1710 for (i=0; i<calleecode->savedadrcount; ++i) {
1711 while (nregdescadr[--reg] != REG_SAV)
1714 *((uintptr_t*) basesp) = es->adrregs[reg];
1716 /* XXX may not clobber saved regs used by native code! */
1717 #if !defined(NDEBUG) && 0
1718 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1725 /* replace_pop_activation_record ***********************************************
1727 Peel a stack frame from the execution state.
1729 *** This function imitates the effects of the method epilog ***
1730 *** and returning from the method call. ***
1733 es...............execution state
1734 frame............source frame, receives synchronization slots
1737 *es..............the execution state after popping the stack frame
1740 the return address of the poped activation record
1742 *******************************************************************************/
1744 u1* replace_pop_activation_record(executionstate_t *es,
1745 sourceframe_t *frame)
1756 /* calculate the base of the stack frame */
1758 sp = (stackslot_t *) es->sp;
1759 assert(frame->syncslotcount == 0);
1760 assert(frame->syncslots == NULL);
1761 count = code_get_sync_slot_count(es->code);
1762 frame->syncslotcount = count;
1763 frame->syncslots = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1764 for (i=0; i<count; ++i) {
1765 frame->syncslots[i].p = *((intptr_t*) (sp + es->code->memuse + i)); /* XXX md_ function */
1768 /* pop the stackframe */
1770 md_pop_stackframe(es);
1774 DOLOG( printf("RA = %p\n", (void*)ra); );
1776 /* Subtract one from the PC so we do not hit the replacement point */
1777 /* of the instruction following the call, if there is one. */
1781 /* find the new codeinfo */
1783 void* pv = md_codegen_get_pv_from_pc(ra);
1784 DOLOG( printf("PV = %p\n", pv); );
1786 code = code_get_codeinfo_for_pv(pv);
1787 DOLOG( printf("CODE = %p\n", (void*) code); );
1789 /* return NULL if we reached native code */
1791 es->pv = (uint8_t*) pv;
1794 return (code) ? ra : NULL;
1798 /* replace_patch_method_pointer ************************************************
1800 Patch a method pointer (may be in code, data segment, vftbl, or interface
1804 mpp..............address of the method pointer to patch
1805 entrypoint.......the new entrypoint of the method
1806 kind.............kind of call to patch, used only for debugging
1808 *******************************************************************************/
1810 static void replace_patch_method_pointer(methodptr *mpp,
1811 methodptr entrypoint,
1814 #if !defined(NDEBUG)
1819 DOLOG( printf("patch method pointer from: %p to %p\n",
1820 (void*) *mpp, (void*)entrypoint); );
1822 #if !defined(NDEBUG)
1823 oldcode = code_get_codeinfo_for_pv(*mpp);
1824 newcode = code_get_codeinfo_for_pv(entrypoint);
1826 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1827 method_println(oldcode->m);
1828 printf("\t with %p ", (void*) newcode);
1829 method_println(newcode->m); );
1831 assert(oldcode->m == newcode->m);
1834 /* write the new entrypoint */
1836 *mpp = (methodptr) entrypoint;
1840 /* replace_patch_class *********************************************************
1842 Patch a method in the given class.
1845 vftbl............vftbl of the class
1846 m................the method to patch
1847 oldentrypoint....the old entrypoint to replace
1848 entrypoint.......the new entrypoint
1850 *******************************************************************************/
1852 void replace_patch_class(vftbl_t *vftbl,
1861 /* patch the vftbl of the class */
1863 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1867 /* patch the interface tables */
1869 assert(oldentrypoint);
1871 for (i=0; i < vftbl->interfacetablelength; ++i) {
1872 mpp = vftbl->interfacetable[-i];
1873 mppend = mpp + vftbl->interfacevftbllength[i];
1874 for (; mpp != mppend; ++mpp)
1875 if (*mpp == oldentrypoint) {
1876 replace_patch_method_pointer(mpp, entrypoint, "interface");
1882 /* replace_patch_class_hierarchy ***********************************************
1884 Patch a method in all loaded classes.
1887 m................the method to patch
1888 oldentrypoint....the old entrypoint to replace
1889 entrypoint.......the new entrypoint
1891 *******************************************************************************/
1893 struct replace_patch_data_t {
1899 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1901 vftbl_t *vftbl = c->vftbl;
1904 && vftbl->vftbllength > pd->m->vftblindex
1905 && (void*) vftbl->table[pd->m->vftblindex] != (void*) (uintptr_t) &asm_abstractmethoderror
1906 && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
1908 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1912 void replace_patch_class_hierarchy(methodinfo *m,
1916 struct replace_patch_data_t pd;
1919 pd.oldentrypoint = oldentrypoint;
1920 pd.entrypoint = entrypoint;
1922 DOLOG_SHORT( printf("patching class hierarchy: ");
1923 method_println(m); );
1925 classcache_foreach_loaded_class(
1926 (classcache_foreach_functionptr_t) &replace_patch_callback,
1931 /* replace_patch_future_calls **************************************************
1933 Analyse a call site and depending on the kind of call patch the call, the
1934 virtual function table, or the interface table.
1937 ra...............return address pointing after the call site
1938 callerframe......source frame of the caller
1939 calleeframe......source frame of the callee, must have been mapped
1941 *******************************************************************************/
1943 void replace_patch_future_calls(u1 *ra,
1944 sourceframe_t *callerframe,
1945 sourceframe_t *calleeframe)
1948 methodptr entrypoint;
1949 methodptr oldentrypoint;
1952 codeinfo *calleecode;
1953 methodinfo *calleem;
1958 assert(callerframe->down == calleeframe);
1960 /* get the new codeinfo and the method that shall be entered */
1962 calleecode = calleeframe->tocode;
1965 calleem = calleeframe->method;
1966 assert(calleem == calleecode->m);
1968 entrypoint = (methodptr) calleecode->entrypoint;
1970 /* check if we are at an method entry rplpoint at the innermost frame */
1972 atentry = (calleeframe->down == NULL)
1973 && !(calleem->flags & ACC_STATIC)
1974 && (calleeframe->fromrp->id == 0); /* XXX */
1976 /* get the position to patch, in case it was a statically bound call */
1978 pv = callerframe->fromcode->entrypoint;
1979 patchpos = (u1*) md_jit_method_patch_address(pv, ra, NULL);
1981 if (patchpos == NULL) {
1982 /* the call was dispatched dynamically */
1984 /* we can only patch such calls if we are at the entry point */
1986 #if !defined(__I386__)
1987 /* On i386 we always know the instance argument. */
1992 assert((calleem->flags & ACC_STATIC) == 0);
1994 oldentrypoint = calleeframe->fromcode->entrypoint;
1996 /* we need to know the instance */
1998 if (!calleeframe->instance.a) {
1999 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
2000 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
2006 obj = calleeframe->instance.a;
2009 assert(vftbl->clazz->vftbl == vftbl);
2011 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->clazz); );
2013 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
2016 /* the call was statically bound */
2018 #if defined(__I386__)
2019 /* It happens that there is a patcher trap. (pm) */
2020 if (*(u2 *)(patchpos - 1) == 0x0b0f) {
2023 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
2028 /* replace_push_activation_record **********************************************
2030 Push a stack frame onto the execution state.
2032 *** This function imitates the effects of a call and the ***
2033 *** method prolog of the callee. ***
2036 es...............execution state
2037 rpcall...........the replacement point at the call site
2038 callerframe......source frame of the caller, or NULL for creating the
2040 calleeframe......source frame of the callee, must have been mapped
2043 *es..............the execution state after pushing the stack frame
2045 *******************************************************************************/
2047 void replace_push_activation_record(executionstate_t *es,
2049 sourceframe_t *callerframe,
2050 sourceframe_t *calleeframe)
2056 codeinfo *calleecode;
2059 assert(!rpcall || callerframe);
2060 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
2061 assert(!rpcall || rpcall == callerframe->torp);
2062 assert(calleeframe);
2063 assert(!callerframe || calleeframe == callerframe->down);
2065 /* the compilation unit we are entering */
2067 calleecode = calleeframe->tocode;
2070 /* calculate the return address */
2073 ra = rpcall->pc + rpcall->callsize;
2075 ra = es->pc + 1 /* XXX this is ugly */;
2077 /* push the stackframe */
2079 md_push_stackframe(es, calleecode, ra);
2081 /* we move into a new code unit, set code, PC, PV */
2083 es->code = calleecode;
2084 es->pc = calleecode->entrypoint; /* XXX not needed? */
2085 es->pv = calleecode->entrypoint;
2087 /* write slots used for synchronization */
2089 sp = (stackslot_t *) es->sp;
2090 count = code_get_sync_slot_count(calleecode);
2091 assert(count == calleeframe->syncslotcount);
2092 for (i=0; i<count; ++i) {
2093 *((intptr_t*) (sp + calleecode->memuse + i)) = calleeframe->syncslots[i].p;
2096 /* redirect future invocations */
2098 if (callerframe && rpcall) {
2099 #if defined(REPLACE_PATCH_ALL)
2100 if (rpcall->type == callerframe->fromrp->type)
2102 if (rpcall == callerframe->fromrp)
2104 replace_patch_future_calls(ra, callerframe, calleeframe);
2109 /* replace_find_replacement_point **********************************************
2111 Find the replacement point in the given code corresponding to the
2112 position given in the source frame.
2115 code.............the codeinfo in which to search the rplpoint
2116 frame............the source frame defining the position to look for
2117 parent...........parent replacement point to match
2120 the replacement point
2122 *******************************************************************************/
2124 rplpoint * replace_find_replacement_point(codeinfo *code,
2125 sourceframe_t *frame,
2138 DOLOG( printf("searching replacement point for:\n");
2139 replace_source_frame_println(frame); );
2143 DOLOG( printf("code = %p\n", (void*)code); );
2145 rp = code->rplpoints;
2146 i = code->rplpointcount;
2148 if (rp->id == frame->id && rp->method == frame->method
2149 && rp->parent == parent
2150 && replace_normalize_type_map[rp->type] == frame->type)
2152 /* check if returnAddresses match */
2153 /* XXX optimize: only do this if JSRs in method */
2154 DOLOG( printf("checking match for:");
2155 replace_replacement_point_println(rp, 1); fflush(stdout); );
2158 for (j = rp->regalloccount; j--; ++ra) {
2159 if (ra->type == TYPE_RET) {
2160 if (ra->index == RPLALLOC_STACK) {
2161 assert(stacki < frame->javastackdepth);
2162 if (frame->javastack[stacki].i != ra->regoff)
2167 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2168 if (frame->javalocals[ra->index].i != ra->regoff)
2181 #if !defined(NDEBUG)
2182 printf("candidate replacement points were:\n");
2183 rp = code->rplpoints;
2184 i = code->rplpointcount;
2186 replace_replacement_point_println(rp, 1);
2190 vm_abort("no matching replacement point found");
2191 return NULL; /* NOT REACHED */
2195 /* replace_find_replacement_point_for_pc ***************************************
2197 Find the nearest replacement point at or before the given PC. The
2198 given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
2199 the replacement point to be found.
2202 code.............compilation unit the PC is in
2203 pc...............the machine code PC
2206 the replacement point found, or
2207 NULL if no replacement point was found
2209 *******************************************************************************/
2211 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc, unsigned desired_flags)
2217 DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
2218 method_println(code->m); );
2222 rp = code->rplpoints;
2223 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2224 DOLOG( replace_replacement_point_println(rp, 2); );
2225 if (rp->pc <= pc && rp->pc + rp->callsize >= pc) {
2226 if (desired_flags) {
2227 if (rp->flags & desired_flags) {
2239 /* replace_pop_native_frame ****************************************************
2241 Unroll a native frame in the execution state and create a source frame
2245 es...............current execution state
2246 ss...............the current source state
2247 sfi..............stackframeinfo for the native frame
2250 es...............execution state after unrolling the native frame
2251 ss...............gets the added native source frame
2253 *******************************************************************************/
2255 static void replace_pop_native_frame(executionstate_t *es,
2257 stackframeinfo_t *sfi)
2259 sourceframe_t *frame;
2265 frame = replace_new_sourceframe(ss);
2269 /* remember pc and size of native frame */
2271 frame->nativepc = es->pc;
2272 frame->nativeframesize = (es->sp != 0) ? (((uintptr_t) sfi->sp) - ((uintptr_t) es->sp)) : 0;
2273 assert(frame->nativeframesize >= 0);
2275 /* remember values of saved registers */
2278 for (i=0; i<INT_REG_CNT; ++i) {
2279 if (nregdescint[i] == REG_SAV)
2280 frame->nativesavint[j++] = es->intregs[i];
2284 for (i=0; i<FLT_REG_CNT; ++i) {
2285 if (nregdescfloat[i] == REG_SAV)
2286 frame->nativesavflt[j++] = es->fltregs[i];
2289 #if defined(HAS_ADDRESS_REGISTER_FILE)
2291 for (i=0; i<ADR_REG_CNT; ++i) {
2292 if (nregdescadr[i] == REG_SAV)
2293 frame->nativesavadr[j++] = es->adrregs[i];
2297 /* restore saved registers */
2299 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2301 for (i=0; i<INT_REG_CNT; ++i) {
2302 if (nregdescint[i] == REG_SAV)
2303 es->intregs[i] = sfi->intregs[j++];
2306 /* XXX we don't have them, yet, in the sfi, so clear them */
2308 for (i=0; i<INT_REG_CNT; ++i) {
2309 if (nregdescint[i] == REG_SAV)
2314 /* XXX we don't have float registers in the sfi, so clear them */
2316 for (i=0; i<FLT_REG_CNT; ++i) {
2317 if (nregdescfloat[i] == REG_SAV)
2318 es->fltregs[i] = 0.0;
2321 #if defined(HAS_ADDRESS_REGISTER_FILE)
2322 # if defined(ENABLE_GC_CACAO)
2324 for (i=0; i<ADR_REG_CNT; ++i) {
2325 if (nregdescadr[i] == REG_SAV)
2326 es->adrregs[i] = sfi->adrregs[j++];
2329 for (i=0; i<ADR_REG_CNT; ++i) {
2330 if (nregdescadr[i] == REG_SAV)
2336 /* restore codeinfo of the native stub */
2338 code = code_get_codeinfo_for_pv(sfi->pv);
2340 /* restore sp, pv, pc and codeinfo of the parent method */
2342 es->sp = (uint8_t*) (((uintptr_t) sfi->sp) + md_stacktrace_get_framesize(code));
2343 #if STACKFRMAE_RA_BETWEEN_FRAMES
2344 es->sp += SIZEOF_VOID_P; /* skip return address */
2346 es->pv = (uint8_t*) md_codegen_get_pv_from_pc(sfi->ra);
2347 es->pc = (uint8_t*) (((uintptr_t) ((sfi->xpc) ? sfi->xpc : sfi->ra)) - 1);
2348 es->code = code_get_codeinfo_for_pv(es->pv);
2352 /* replace_push_native_frame ***************************************************
2354 Rebuild a native frame onto the execution state and remove its source frame.
2356 Note: The native frame is "rebuild" by setting fields like PC and stack
2357 pointer in the execution state accordingly. Values in the
2358 stackframeinfo may be modified, but the actual stack frame of the
2359 native code is not touched.
2362 es...............current execution state
2363 ss...............the current source state
2366 es...............execution state after re-rolling the native frame
2367 ss...............the native source frame is removed
2369 *******************************************************************************/
2371 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2373 sourceframe_t *frame;
2379 DOLOG( printf("pushing native frame\n"); );
2381 /* remove the frame from the source state */
2385 assert(REPLACE_IS_NATIVE_FRAME(frame));
2387 ss->frames = frame->down;
2389 /* skip sp for the native stub */
2391 es->sp -= md_stacktrace_get_framesize(frame->sfi->code);
2392 #if STACKFRMAE_RA_BETWEEN_FRAMES
2393 es->sp -= SIZEOF_VOID_P; /* skip return address */
2396 /* assert that the native frame has not moved */
2398 assert(es->sp == frame->sfi->sp);
2400 /* update saved registers in the stackframeinfo */
2402 #if defined(ENABLE_GC_CACAO)
2404 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2405 for (i=0; i<INT_REG_CNT; ++i) {
2406 if (nregdescint[i] == REG_SAV)
2407 frame->sfi->intregs[j++] = es->intregs[i];
2410 for (i=0; i<ADR_REG_CNT; ++i) {
2411 if (nregdescadr[i] == REG_SAV)
2412 frame->sfi->adrregs[j++] = es->adrregs[i];
2416 /* XXX leave float registers untouched here */
2419 /* restore saved registers */
2422 for (i=0; i<INT_REG_CNT; ++i) {
2423 if (nregdescint[i] == REG_SAV)
2424 es->intregs[i] = frame->nativesavint[j++];
2428 for (i=0; i<FLT_REG_CNT; ++i) {
2429 if (nregdescfloat[i] == REG_SAV)
2430 es->fltregs[i] = frame->nativesavflt[j++];
2433 #if defined(HAS_ADDRESS_REGISTER_FILE)
2435 for (i=0; i<ADR_REG_CNT; ++i) {
2436 if (nregdescadr[i] == REG_SAV)
2437 es->adrregs[i] = frame->nativesavadr[j++];
2441 /* skip the native frame on the machine stack */
2443 es->sp -= frame->nativeframesize;
2445 /* set the pc the next frame must return to */
2447 es->pc = frame->nativepc;
2451 /* replace_recover_source_state ************************************************
2453 Recover the source state from the given replacement point and execution
2457 rp...............replacement point that has been reached, if any
2458 sfi..............stackframeinfo, if called from native code
2459 es...............execution state at the replacement point rp
2464 *******************************************************************************/
2466 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2467 stackframeinfo_t *sfi,
2468 executionstate_t *es)
2473 #if defined(REPLACE_STATISTICS)
2477 /* create the source frame structure in dump memory */
2479 ss = (sourcestate_t*) DumpMemory::allocate(sizeof(sourcestate_t));
2482 /* each iteration of the loop recovers one source frame */
2489 DOLOG( executionstate_println(es); );
2491 /* if we are not at a replacement point, it is a native frame */
2494 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2497 replace_pop_native_frame(es, ss, sfi);
2500 if (es->code == NULL)
2503 goto after_machine_frame;
2506 /* read the values for this source frame from the execution state */
2508 DOLOG( printf("recovering source state for%s:\n",
2509 (ss->frames == NULL) ? " TOPFRAME" : "");
2510 replace_replacement_point_println(rp, 1); );
2512 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2514 #if defined(ENABLE_VMLOG)
2515 vmlog_cacao_unrol_method(ss->frames->method);
2518 #if defined(REPLACE_STATISTICS)
2519 REPLACE_COUNT(stat_frames);
2521 replace_statistics_source_frame(ss->frames);
2524 /* in locked areas (below native frames), identity map the frame */
2527 ss->frames->torp = ss->frames->fromrp;
2528 ss->frames->tocode = ss->frames->fromcode;
2531 /* unroll to the next (outer) frame */
2534 /* this frame is in inlined code */
2536 DOLOG( printf("INLINED!\n"); );
2540 assert(rp->type == RPLPOINT_TYPE_INLINE);
2541 REPLACE_COUNT(stat_unroll_inline);
2544 /* this frame had been called at machine-level. pop it. */
2546 DOLOG( printf("UNWIND\n"); );
2548 ra = replace_pop_activation_record(es, ss->frames);
2550 DOLOG( printf("REACHED NATIVE CODE\n"); );
2554 #if !defined(ENABLE_GC_CACAO)
2555 break; /* XXX remove to activate native frames */
2560 /* find the replacement point at the call site */
2562 after_machine_frame:
2563 rp = replace_find_replacement_point_for_pc(es->code, es->pc, 0);
2566 vm_abort("could not find replacement point while unrolling call");
2568 DOLOG( printf("found replacement point.\n");
2569 replace_replacement_point_println(rp, 1); );
2571 assert(rp->type == RPLPOINT_TYPE_CALL);
2572 REPLACE_COUNT(stat_unroll_call);
2574 } /* end loop over source frames */
2576 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2582 /* replace_map_source_state ****************************************************
2584 Map each source frame in the given source state to a target replacement
2585 point and compilation unit. If no valid code is available for a source
2586 frame, it is (re)compiled.
2589 ss...............the source state
2592 ss...............the source state, modified: The `torp` and `tocode`
2593 fields of each source frame are set.
2596 true.............everything went ok
2597 false............an exception has been thrown
2599 *******************************************************************************/
2601 static bool replace_map_source_state(sourcestate_t *ss)
2603 sourceframe_t *frame;
2606 rplpoint *parent; /* parent of inlined rplpoint */
2607 #if defined(REPLACE_STATISTICS)
2614 /* iterate over the source frames from outermost to innermost */
2616 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2618 /* XXX skip native frames */
2620 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2625 /* map frames which are not already mapped */
2627 if (frame->tocode) {
2628 code = frame->tocode;
2633 assert(frame->torp == NULL);
2635 if (parent == NULL) {
2636 /* find code for this frame */
2638 #if defined(REPLACE_STATISTICS)
2639 oldcode = frame->method->code;
2641 /* request optimization of hot methods and their callers */
2643 if (frame->method->hitcountdown < 0
2644 || (frame->down && frame->down->method->hitcountdown < 0))
2645 jit_request_optimization(frame->method);
2647 code = jit_get_current_code(frame->method);
2650 return false; /* exception */
2652 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2657 /* map this frame */
2659 rp = replace_find_replacement_point(code, frame, parent);
2661 frame->tocode = code;
2665 if (rp->type == RPLPOINT_TYPE_CALL) {
2678 /* replace_map_source_state_identity *******************************************
2680 Map each source frame in the given source state to the same replacement
2681 point and compilation unit it was derived from. This is mainly used for
2685 ss...............the source state
2688 ss...............the source state, modified: The `torp` and `tocode`
2689 fields of each source frame are set.
2691 *******************************************************************************/
2693 #if defined(ENABLE_GC_CACAO)
2694 static void replace_map_source_state_identity(sourcestate_t *ss)
2696 sourceframe_t *frame;
2698 /* iterate over the source frames from outermost to innermost */
2700 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2702 /* skip native frames */
2704 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2708 /* map frames using the identity mapping */
2710 if (frame->tocode) {
2711 assert(frame->tocode == frame->fromcode);
2712 assert(frame->torp == frame->fromrp);
2714 assert(frame->tocode == NULL);
2715 assert(frame->torp == NULL);
2716 frame->tocode = frame->fromcode;
2717 frame->torp = frame->fromrp;
2724 /* replace_build_execution_state ***********************************************
2726 Build an execution state for the given (mapped) source state.
2728 !!! CAUTION: This function rewrites the machine stack !!!
2730 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2733 ss...............the source state. Must have been mapped by
2734 replace_map_source_state before.
2735 es...............the base execution state on which to build
2738 *es..............the new execution state
2740 *******************************************************************************/
2742 static void replace_build_execution_state(sourcestate_t *ss,
2743 executionstate_t *es)
2746 sourceframe_t *prevframe;
2753 while (ss->frames) {
2755 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2756 prevframe = ss->frames;
2757 replace_push_native_frame(es, ss);
2763 if (parent == NULL) {
2764 /* create a machine-level stack frame */
2766 DOLOG( printf("pushing activation record for:\n");
2767 if (rp) replace_replacement_point_println(rp, 1);
2768 else printf("\tfirst frame\n"); );
2770 replace_push_activation_record(es, rp, prevframe, ss->frames);
2772 DOLOG( executionstate_println(es); );
2775 rp = ss->frames->torp;
2778 DOLOG( printf("creating execution state for%s:\n",
2779 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2780 replace_replacement_point_println(ss->frames->fromrp, 1);
2781 replace_replacement_point_println(rp, 1); );
2783 es->code = ss->frames->tocode;
2784 prevframe = ss->frames;
2786 #if defined(ENABLE_VMLOG)
2787 vmlog_cacao_rerol_method(ss->frames->method);
2790 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2792 DOLOG( executionstate_println(es); );
2794 if (rp->type == RPLPOINT_TYPE_CALL) {
2805 /* replace_me ******************************************************************
2807 This function is called by the signal handler when a thread reaches
2808 a replacement point. `replace_me` must map the execution state to the
2809 target replacement point and let execution continue there.
2811 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2814 rp...............replacement point that has been reached
2815 es...............execution state read by signal handler
2817 *******************************************************************************/
2819 static void replace_me(rplpoint *rp, executionstate_t *es)
2821 stackframeinfo_t *sfi;
2823 sourceframe_t *frame;
2826 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2827 threadobject *thread;
2830 origcode = es->code;
2833 #if defined(ENABLE_TLH)
2834 /*printf("Replacing in %s/%s\n", rp->method->clazz->name->text, rp->method->name->text);*/
2837 /*if (strcmp(rp->method->clazz->name->text, "antlr/AlternativeElement") == 0 && strcmp(rp->method->name->text, "getAutoGenType") ==0) opt_TraceReplacement = 2; else opt_TraceReplacement = 0;*/
2839 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2840 stat_replacements, (void*)THREADOBJECT,
2842 method_println(es->code->m); );
2844 DOLOG( replace_replacement_point_println(rp, 1); );
2846 REPLACE_COUNT(stat_replacements);
2848 // Create new dump memory area.
2851 /* Get the stackframeinfo for the current thread. */
2853 sfi = threads_get_current_stackframeinfo();
2855 /* recover source state */
2857 ss = replace_recover_source_state(rp, sfi, es);
2859 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2860 /* if there is a collection pending, we assume the replacement point should
2861 suspend this thread */
2865 thread = THREADOBJECT;
2867 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2869 /* map the sourcestate using the identity mapping */
2870 replace_map_source_state_identity(ss);
2872 /* since we enter the same method again, we turn off rps now */
2873 /* XXX michi: can we really do this? what if the rp was active before
2874 we activated it for the gc? */
2875 replace_deactivate_replacement_points(origcode);
2877 /* remember executionstate and sourcestate for this thread */
2878 GC_EXECUTIONSTATE = es;
2879 GC_SOURCESTATE = ss;
2881 /* really suspend this thread now (PC = 0) */
2882 threads_suspend_ack(NULL, NULL);
2884 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2887 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2889 /* map the source state */
2891 if (!replace_map_source_state(ss))
2892 vm_abort("exception during method replacement");
2894 DOLOG( replace_sourcestate_println(ss); );
2896 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2898 #if !defined(NDEBUG)
2899 /* avoid infinite loops by self-replacement, only if not in testing mode */
2901 if (!opt_TestReplacement) {
2904 frame = frame->down;
2906 if (frame->torp == origrp) {
2908 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2910 replace_deactivate_replacement_points(origcode);
2915 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2919 /* build the new execution state */
2921 replace_build_execution_state(ss, es);
2923 #if !defined(NDEBUG)
2924 /* continue execution after patched machine code, if testing mode enabled */
2926 if (opt_TestReplacement)
2927 es->pc += REPLACEMENT_PATCH_SIZE;
2932 /* replace_handler *************************************************************
2934 This function is called by the signal handler. It determines if there
2935 is an active replacement point pending at the given PC and returns
2938 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2941 pc...............the program counter that triggered the replacement.
2942 es...............the execution state (machine state) to which the
2943 replacement should be applied.
2946 es...............the execution state after replacement finished.
2949 true.............replacement done, everything went ok
2950 false............no replacement done, execution state unchanged
2952 *******************************************************************************/
2954 bool replace_handler(u1 *pc, executionstate_t *es)
2958 #if defined(ENABLE_RT_TIMING)
2959 struct timespec time_start, time_end;
2962 /* search the codeinfo for the given PC */
2964 code = code_find_codeinfo_for_pc(pc);
2967 /* search for a replacement point at the given PC */
2969 rp = replace_find_replacement_point_for_pc(code, pc, (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN));
2971 /* check if the replacement point belongs to given PC and is active */
2973 if ((rp != NULL) && (rp->pc == pc)
2974 && (rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))) {
2976 DOLOG( printf("valid replacement point\n"); );
2978 /* set codeinfo pointer in execution state */
2982 /* do the actual replacement */
2984 #if defined(ENABLE_RT_TIMING)
2985 RT_TIMING_GET_TIME(time_start);
2990 #if defined(ENABLE_RT_TIMING)
2991 RT_TIMING_GET_TIME(time_end);
2992 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_REPLACE);
2995 /* new code is entered after returning */
2997 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
3005 /******************************************************************************/
3006 /* NOTE: Stuff specific to the exact GC is below. */
3007 /******************************************************************************/
3009 #if defined(ENABLE_GC_CACAO)
3010 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
3012 stackframeinfo_t *sfi;
3013 executionstate_t *es;
3016 /* Get the stackframeinfo of this thread. */
3018 assert(thread == THREADOBJECT);
3020 sfi = threads_get_current_stackframeinfo();
3022 /* create the execution state */
3023 es = (executionstate_t*) DumpMemory::allocate(sizeof(executionstate_t));
3026 es->pv = 0; /* since we are in a native, PV is invalid! */
3027 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
3029 /* we assume we are in a native (no replacement point)! */
3030 ss = replace_recover_source_state(NULL, sfi, es);
3032 /* map the sourcestate using the identity mapping */
3033 replace_map_source_state_identity(ss);
3035 /* remember executionstate and sourcestate for this thread */
3036 GC_EXECUTIONSTATE = es;
3037 GC_SOURCESTATE = ss;
3041 #if defined(ENABLE_GC_CACAO)
3042 void replace_gc_into_native(threadobject *thread)
3044 executionstate_t *es;
3047 /* get the executionstate and sourcestate for the given thread */
3048 es = GC_EXECUTIONSTATE;
3049 ss = GC_SOURCESTATE;
3051 /* rebuild the stack of the given thread */
3052 replace_build_execution_state(ss, es);
3057 /******************************************************************************/
3058 /* NOTE: No important code below. */
3059 /******************************************************************************/
3062 /* statistics *****************************************************************/
3064 #if defined(REPLACE_STATISTICS)
3065 static void print_freq(FILE *file,int *array,int limit)
3070 for (i=0; i<limit; ++i)
3072 sum += array[limit];
3073 for (i=0; i<limit; ++i) {
3075 fprintf(file," %3d: %8d (cum %3d%%)\n",
3076 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3078 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
3080 #endif /* defined(REPLACE_STATISTICS) */
3083 #if defined(REPLACE_STATISTICS)
3085 #define REPLACE_PRINT_DIST(name, array) \
3086 printf(" " name " distribution:\n"); \
3087 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3089 void replace_print_statistics(void)
3091 printf("replacement statistics:\n");
3092 printf(" # of replacements: %d\n", stat_replacements);
3093 printf(" # of frames: %d\n", stat_frames);
3094 printf(" # of recompilations: %d\n", stat_recompile);
3095 printf(" patched static calls:%d\n", stat_staticpatch);
3096 printf(" unrolled inlines: %d\n", stat_unroll_inline);
3097 printf(" unrolled calls: %d\n", stat_unroll_call);
3098 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3099 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3100 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3101 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3102 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3103 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3104 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3105 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3106 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3107 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3109 printf(" # of methods: %d\n", stat_methods);
3110 printf(" # of replacement points: %d\n", stat_rploints);
3111 printf(" # of regallocs: %d\n", stat_regallocs);
3112 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
3113 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
3114 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3118 #endif /* defined(REPLACE_STATISTICS) */
3121 #if defined(REPLACE_STATISTICS)
3122 static void replace_statistics_source_frame(sourceframe_t *frame)
3131 for (i=0; i<frame->javalocalcount; ++i) {
3132 switch (frame->javalocaltype[i]) {
3133 case TYPE_ADR: adr++; break;
3134 case TYPE_RET: ret++; break;
3135 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3136 case TYPE_VOID: vd++; break;
3141 REPLACE_COUNT_DIST(stat_dist_locals, n);
3142 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3143 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3144 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3145 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3146 adr = ret = prim = n = 0;
3147 for (i=0; i<frame->javastackdepth; ++i) {
3148 switch (frame->javastacktype[i]) {
3149 case TYPE_ADR: adr++; break;
3150 case TYPE_RET: ret++; break;
3151 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3155 REPLACE_COUNT_DIST(stat_dist_stack, n);
3156 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3157 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3158 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3160 #endif /* defined(REPLACE_STATISTICS) */
3163 /* debugging helpers **********************************************************/
3165 /* replace_replacement_point_println *******************************************
3167 Print replacement point info.
3170 rp...............the replacement point to print
3172 *******************************************************************************/
3174 #if !defined(NDEBUG)
3176 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3178 static const char *replace_type_str[] = {
3188 void replace_replacement_point_println(rplpoint *rp, int depth)
3194 printf("(rplpoint *)NULL\n");
3198 for (j=0; j<depth; ++j)
3201 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3202 rp->id, (void*)rp,rp->pc,rp->callsize,
3203 replace_type_str[rp->type]);
3204 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3206 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3207 printf(" COUNTDOWN");
3208 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3210 printf(" parent:%p\n", (void*)rp->parent);
3211 for (j=0; j<depth; ++j)
3213 printf("ra:%d = [", rp->regalloccount);
3215 for (j=0; j<rp->regalloccount; ++j) {
3218 index = rp->regalloc[j].index;
3220 case RPLALLOC_STACK: printf("S"); break;
3221 case RPLALLOC_PARAM: printf("P"); break;
3222 case RPLALLOC_SYNC : printf("Y"); break;
3223 default: printf("%d", index);
3225 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3226 if (rp->regalloc[j].type == TYPE_RET) {
3227 printf("ret(L%03d)", rp->regalloc[j].regoff);
3230 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3235 for (j=0; j<depth; ++j)
3238 method_print(rp->method);
3242 #endif /* !defined(NDEBUG) */
3245 /* replace_show_replacement_points *********************************************
3247 Print replacement point info.
3250 code.............codeinfo whose replacement points should be printed.
3252 *******************************************************************************/
3254 #if !defined(NDEBUG)
3255 void replace_show_replacement_points(codeinfo *code)
3263 printf("(codeinfo *)NULL\n");
3267 printf("\treplacement points: %d\n",code->rplpointcount);
3269 printf("\ttotal allocations : %d\n",code->regalloccount);
3270 printf("\tsaved int regs : %d\n",code->savedintcount);
3271 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3272 #if defined(HAS_ADDRESS_REGISTER_FILE)
3273 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3275 printf("\tmemuse : %d\n",code->memuse);
3279 for (i=0; i<code->rplpointcount; ++i) {
3280 rp = code->rplpoints + i;
3283 parent = rp->parent;
3286 parent = parent->parent;
3288 replace_replacement_point_println(rp, depth);
3294 #if !defined(NDEBUG)
3295 static void java_value_print(s4 type, replace_val_t value)
3300 printf("%016llx",(unsigned long long) value.l);
3302 if (type < 0 || type > TYPE_RET)
3303 printf(" <INVALID TYPE:%d>", type);
3305 printf(" %s", show_jit_type_names[type]);
3307 if (type == TYPE_ADR && value.a != NULL) {
3310 utf_display_printable_ascii_classname(obj->vftbl->clazz->name);
3312 if (obj->vftbl->clazz == class_java_lang_String) {
3314 u = javastring_toutf(obj, false);
3315 utf_display_printable_ascii(u);
3319 else if (type == TYPE_INT) {
3320 printf(" %ld", (long) value.i);
3322 else if (type == TYPE_LNG) {
3323 printf(" %lld", (long long) value.l);
3325 else if (type == TYPE_FLT) {
3326 printf(" %f", value.f);
3328 else if (type == TYPE_DBL) {
3329 printf(" %f", value.d);
3332 #endif /* !defined(NDEBUG) */
3335 #if !defined(NDEBUG)
3336 void replace_source_frame_println(sourceframe_t *frame)
3341 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3342 printf("\tNATIVE\n");
3343 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3344 printf("\tnativepc: %p\n", frame->nativepc);
3345 printf("\tframesize: %d\n", frame->nativeframesize);
3348 for (i=0; i<INT_REG_CNT; ++i) {
3349 if (nregdescint[i] == REG_SAV)
3350 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3354 for (i=0; i<FLT_REG_CNT; ++i) {
3355 if (nregdescfloat[i] == REG_SAV)
3356 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3364 method_println(frame->method);
3365 printf("\tid: %d\n", frame->id);
3366 printf("\ttype: %s\n", replace_type_str[frame->type]);
3369 if (frame->instance.a) {
3370 printf("\tinstance: ");
3371 java_value_print(TYPE_ADR, frame->instance);
3375 if (frame->javalocalcount) {
3376 printf("\tlocals (%d):\n",frame->javalocalcount);
3377 for (i=0; i<frame->javalocalcount; ++i) {
3378 t = frame->javalocaltype[i];
3379 if (t == TYPE_VOID) {
3380 printf("\tlocal[ %2d] = void\n",i);
3383 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3384 java_value_print(t, frame->javalocals[i]);
3391 if (frame->javastackdepth) {
3392 printf("\tstack (depth %d):\n",frame->javastackdepth);
3393 for (i=0; i<frame->javastackdepth; ++i) {
3394 t = frame->javastacktype[i];
3395 if (t == TYPE_VOID) {
3396 printf("\tstack[%2d] = void", i);
3399 printf("\tstack[%2d] = ",i);
3400 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3407 if (frame->syncslotcount) {
3408 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3409 for (i=0; i<frame->syncslotcount; ++i) {
3410 printf("\tslot[%2d] = %016llx\n",i,(unsigned long long) frame->syncslots[i].p);
3415 if (frame->fromcode) {
3416 printf("\tfrom %p ", (void*)frame->fromcode);
3417 method_println(frame->fromcode->m);
3419 if (frame->tocode) {
3420 printf("\tto %p ", (void*)frame->tocode);
3421 method_println(frame->tocode->m);
3424 if (frame->fromrp) {
3425 printf("\tfrom replacement point:\n");
3426 replace_replacement_point_println(frame->fromrp, 2);
3429 printf("\tto replacement point:\n");
3430 replace_replacement_point_println(frame->torp, 2);
3435 #endif /* !defined(NDEBUG) */
3438 /* replace_sourcestate_println *************************************************
3443 ss...............the source state to print
3445 *******************************************************************************/
3447 #if !defined(NDEBUG)
3448 void replace_sourcestate_println(sourcestate_t *ss)
3451 sourceframe_t *frame;
3454 printf("(sourcestate_t *)NULL\n");
3458 printf("sourcestate_t:\n");
3460 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3461 printf(" frame %d:\n", i);
3462 replace_source_frame_println(frame);
3468 /* replace_sourcestate_println_short *******************************************
3470 Print a compact representation of the given source state.
3473 ss...............the source state to print
3475 *******************************************************************************/
3477 #if !defined(NDEBUG)
3478 void replace_sourcestate_println_short(sourcestate_t *ss)
3480 sourceframe_t *frame;
3482 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3485 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3486 printf("NATIVE (pc %p size %d) ",
3487 (void*)frame->nativepc, frame->nativeframesize);
3488 replace_stackframeinfo_println(frame->sfi);
3493 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3496 printf("%s", replace_type_str[frame->fromrp->type]);
3498 if (frame->torp && frame->torp->type != frame->fromrp->type)
3499 printf("->%s", replace_type_str[frame->torp->type]);
3501 if (frame->tocode != frame->fromcode)
3502 printf(" (%p->%p/%d) ",
3503 (void*) frame->fromcode, (void*) frame->tocode,
3506 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3508 method_println(frame->method);
3513 #if !defined(NDEBUG)
3514 static void replace_stackframeinfo_println(stackframeinfo_t *sfi)
3516 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3517 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3518 (void*)sfi->ra, (void*)sfi->xpc);
3521 method_println(sfi->code->m);
3529 * These are local overrides for various environment variables in Emacs.
3530 * Please do not remove this and leave it at the end of the file, where
3531 * Emacs will automagically detect them.
3532 * ---------------------------------------------------------------------
3535 * indent-tabs-mode: t
3539 * vim:noexpandtab:sw=4:ts=4: