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 /*** debugging ****************************************************************/
78 static void java_value_print(s4 type, replace_val_t value);
79 static void replace_stackframeinfo_println(stackframeinfo_t *sfi);
83 #define DOLOG(code) do{ if (opt_TraceReplacement > 1) { code; } } while(0)
84 #define DOLOG_SHORT(code) do{ if (opt_TraceReplacement > 0) { code; } } while(0)
87 #define DOLOG_SHORT(code)
91 /*** statistics ***************************************************************/
93 #define REPLACE_STATISTICS
95 #if defined(REPLACE_STATISTICS)
97 static int stat_replacements = 0;
98 static int stat_frames = 0;
99 static int stat_recompile = 0;
100 static int stat_staticpatch = 0;
101 static int stat_unroll_inline = 0;
102 static int stat_unroll_call = 0;
103 static int stat_dist_frames[20] = { 0 };
104 static int stat_dist_locals[20] = { 0 };
105 static int stat_dist_locals_adr[10] = { 0 };
106 static int stat_dist_locals_prim[10] = { 0 };
107 static int stat_dist_locals_ret[10] = { 0 };
108 static int stat_dist_locals_void[10] = { 0 };
109 static int stat_dist_stack[10] = { 0 };
110 static int stat_dist_stack_adr[10] = { 0 };
111 static int stat_dist_stack_prim[10] = { 0 };
112 static int stat_dist_stack_ret[10] = { 0 };
113 static int stat_methods = 0;
114 static int stat_rploints = 0;
115 static int stat_regallocs = 0;
116 static int stat_dist_method_rplpoints[20] = { 0 };
118 #define REPLACE_COUNT(cnt) (cnt)++
119 #define REPLACE_COUNT_IF(cnt, cond) do{ if(cond) (cnt)++; } while(0)
120 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
122 #define REPLACE_COUNT_DIST(array, val) \
124 int limit = (sizeof(array) / sizeof(int)) - 1; \
125 if ((val) < (limit)) (array)[val]++; \
126 else (array)[limit]++; \
129 static void replace_statistics_source_frame(sourceframe_t *frame);
133 #define REPLACE_COUNT(cnt)
134 #define REPLACE_COUNT_IF(cnt, cond)
135 #define REPLACE_COUNT_INC(cnt, inc)
136 #define REPLACE_COUNT_DIST(array, val)
138 #endif /* defined(REPLACE_STATISTICS) */
141 /*** constants used internally ************************************************/
143 #define TOP_IS_NORMAL 0
144 #define TOP_IS_ON_STACK 1
145 #define TOP_IS_IN_ITMP1 2
146 #define TOP_IS_VOID 3
149 /******************************************************************************/
150 /* PART I: Creating / freeing replacement points */
151 /******************************************************************************/
154 /* replace_create_replacement_point ********************************************
156 Create a replacement point.
159 jd...............current jitdata
160 iinfo............inlining info for the current position
161 rp...............pre-allocated (uninitialized) rplpoint
162 type.............RPLPOINT_TYPE constant
163 iptr.............current instruction
164 *pra.............current rplalloc pointer
165 javalocals.......the javalocals at the current point
166 stackvars........the stack variables at the current point
167 stackdepth.......the stack depth at the current point
168 paramcount.......number of parameters at the start of stackvars
171 *rpa.............points to the next free rplalloc
173 *******************************************************************************/
175 static void replace_create_replacement_point(jitdata *jd,
176 insinfo_inline *iinfo,
193 REPLACE_COUNT(stat_rploints);
195 rp->method = (iinfo) ? iinfo->method : jd->m;
196 rp->pc = NULL; /* set by codegen */
197 rp->callsize = 0; /* set by codegen */
201 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
203 /* XXX unify these two fields */
204 rp->parent = (iinfo) ? iinfo->rp : NULL;
206 /* store local allocation info of javalocals */
209 for (i = 0; i < rp->method->maxlocals; ++i) {
210 index = javalocals[i];
217 ra->flags = v->flags & (INMEMORY);
218 ra->regoff = v->vv.regoff;
222 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
230 /* store allocation info of java stack vars */
232 for (i = 0; i < stackdepth; ++i) {
233 v = VAR(stackvars[i]);
234 ra->flags = v->flags & (INMEMORY);
235 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
237 /* XXX how to handle locals on the stack containing returnAddresses? */
238 if (v->type == TYPE_RET) {
239 assert(stackvars[i] >= jd->localcount);
240 ra->regoff = v->vv.retaddr->nr;
243 ra->regoff = v->vv.regoff;
247 /* total number of allocations */
249 rp->regalloccount = ra - rp->regalloc;
255 /* replace_create_inline_start_replacement_point *******************************
257 Create an INLINE_START replacement point.
260 jd...............current jitdata
261 rp...............pre-allocated (uninitialized) rplpoint
262 iptr.............current instruction
263 *pra.............current rplalloc pointer
264 javalocals.......the javalocals at the current point
267 *rpa.............points to the next free rplalloc
270 the insinfo_inline * for the following inlined body
272 *******************************************************************************/
274 static insinfo_inline * replace_create_inline_start_replacement_point(
281 insinfo_inline *calleeinfo;
284 calleeinfo = iptr->sx.s23.s3.inlineinfo;
288 replace_create_replacement_point(jd, calleeinfo->parent, rp,
289 RPLPOINT_TYPE_INLINE, iptr, pra,
291 calleeinfo->stackvars, calleeinfo->stackvarscount,
292 calleeinfo->paramcount);
294 if (calleeinfo->synclocal != UNUSED) {
296 ra->index = RPLALLOC_SYNC;
297 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
298 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
308 /* replace_create_replacement_points *******************************************
310 Create the replacement points for the given code.
313 jd...............current jitdata, must not have any replacement points
316 code->rplpoints.......set to the list of replacement points
317 code->rplpointcount...number of replacement points
318 code->regalloc........list of allocation info
319 code->regalloccount...total length of allocation info list
320 code->globalcount.....number of global allocations at the
321 start of code->regalloc
324 true.............everything ok
325 false............an exception has been thrown
327 *******************************************************************************/
329 #define CLEAR_javalocals(array, method) \
331 for (i=0; i<(method)->maxlocals; ++i) \
332 (array)[i] = UNUSED; \
335 #define COPY_OR_CLEAR_javalocals(dest, array, method) \
337 if ((array) != NULL) \
338 MCOPY((dest), (array), s4, (method)->maxlocals); \
340 CLEAR_javalocals((dest), (method)); \
343 #define COUNT_javalocals(array, method, counter) \
345 for (i=0; i<(method)->maxlocals; ++i) \
346 if ((array)[i] != UNUSED) \
350 bool replace_create_replacement_points(jitdata *jd)
368 insinfo_inline *iinfo;
371 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
375 REPLACE_COUNT(stat_methods);
377 /* get required compiler data */
382 /* assert that we wont overwrite already allocated data */
386 assert(code->rplpoints == NULL);
387 assert(code->rplpointcount == 0);
388 assert(code->regalloc == NULL);
389 assert(code->regalloccount == 0);
390 assert(code->globalcount == 0);
394 /* in instance methods, we may need a rplpoint at the method entry */
396 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
397 if (!(m->flags & ACC_STATIC)) {
398 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
404 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
406 /* iterate over the basic block list to find replacement points */
411 javalocals = (s4*) DumpMemory::allocate(sizeof(s4) * jd->maxlocals);
413 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
417 if (bptr->flags < BBFINISHED)
420 /* get info about this block */
423 iinfo = bptr->inlineinfo;
425 /* initialize javalocals at the start of this block */
427 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
429 /* iterate over the instructions */
432 iend = iptr + bptr->icount;
436 for (; iptr != iend; ++iptr) {
438 #if defined(ENABLE_GC_CACAO)
440 md = iptr->sx.s23.s3.bte->md;
442 COUNT_javalocals(javalocals, m, alloccount);
443 alloccount += iptr->s1.argcount;
445 alloccount -= iinfo->throughcount;
449 case ICMD_INVOKESTATIC:
450 case ICMD_INVOKESPECIAL:
451 case ICMD_INVOKEVIRTUAL:
452 case ICMD_INVOKEINTERFACE:
453 INSTRUCTION_GET_METHODDESC(iptr, md);
455 COUNT_javalocals(javalocals, m, alloccount);
456 alloccount += iptr->s1.argcount;
458 alloccount -= iinfo->throughcount;
466 stack_javalocals_store(iptr, javalocals);
480 case ICMD_INLINE_START:
481 iinfo = iptr->sx.s23.s3.inlineinfo;
484 COUNT_javalocals(javalocals, m, alloccount);
485 alloccount += iinfo->stackvarscount;
486 if (iinfo->synclocal != UNUSED)
490 /* javalocals may be set at next block start, or now */
491 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
494 case ICMD_INLINE_BODY:
495 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
497 jl = iinfo->javalocals_start;
499 /* get the javalocals from the following block start */
501 jl = bptr->next->javalocals;
504 COUNT_javalocals(jl, m, alloccount);
507 case ICMD_INLINE_END:
508 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
509 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
510 iinfo = iptr->sx.s23.s3.inlineinfo;
512 if (iinfo->javalocals_end)
513 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
514 iinfo = iinfo->parent;
518 if (iptr == bptr->iinstr)
520 } /* end instruction loop */
522 /* create replacement points at targets of backward branches */
523 /* We only need the replacement point there, if there is no */
524 /* replacement point inside the block. */
526 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
527 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
528 int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
532 if (test > startcount) {
533 /* we don't need an extra rplpoint */
534 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
538 alloccount += bptr->indepth;
539 if (bptr->inlineinfo)
540 alloccount -= bptr->inlineinfo->throughcount;
542 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
546 } /* end basicblock loop */
548 /* if no points were found, there's nothing to do */
553 /* allocate replacement point array and allocation array */
555 rplpoints = MNEW(rplpoint, count);
556 regalloc = MNEW(rplalloc, alloccount);
559 /* initialize replacement point structs */
563 /* XXX try to share code with the counting loop! */
565 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
568 if (bptr->flags < BBFINISHED)
571 /* get info about this block */
574 iinfo = bptr->inlineinfo;
576 /* initialize javalocals at the start of this block */
578 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
580 /* create replacement points at targets of backward branches */
582 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
584 i = (iinfo) ? iinfo->throughcount : 0;
585 replace_create_replacement_point(jd, iinfo, rp++,
586 bptr->type, bptr->iinstr, &ra,
587 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
589 if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
590 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
593 /* iterate over the instructions */
596 iend = iptr + bptr->icount;
598 for (; iptr != iend; ++iptr) {
600 #if defined(ENABLE_GC_CACAO)
602 md = iptr->sx.s23.s3.bte->md;
604 i = (iinfo) ? iinfo->throughcount : 0;
605 replace_create_replacement_point(jd, iinfo, rp++,
606 RPLPOINT_TYPE_CALL, iptr, &ra,
607 javalocals, iptr->sx.s23.s2.args,
608 iptr->s1.argcount - i,
613 case ICMD_INVOKESTATIC:
614 case ICMD_INVOKESPECIAL:
615 case ICMD_INVOKEVIRTUAL:
616 case ICMD_INVOKEINTERFACE:
617 INSTRUCTION_GET_METHODDESC(iptr, md);
619 i = (iinfo) ? iinfo->throughcount : 0;
620 replace_create_replacement_point(jd, iinfo, rp++,
621 RPLPOINT_TYPE_CALL, iptr, &ra,
622 javalocals, iptr->sx.s23.s2.args,
623 iptr->s1.argcount - i,
632 stack_javalocals_store(iptr, javalocals);
640 replace_create_replacement_point(jd, iinfo, rp++,
641 RPLPOINT_TYPE_RETURN, iptr, &ra,
642 NULL, &(iptr->s1.varindex), 1, 0);
646 replace_create_replacement_point(jd, iinfo, rp++,
647 RPLPOINT_TYPE_RETURN, iptr, &ra,
651 case ICMD_INLINE_START:
652 iinfo = replace_create_inline_start_replacement_point(
653 jd, rp++, iptr, &ra, javalocals);
655 /* javalocals may be set at next block start, or now */
656 COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
659 case ICMD_INLINE_BODY:
660 assert(iinfo == iptr->sx.s23.s3.inlineinfo);
662 jl = iinfo->javalocals_start;
664 /* get the javalocals from the following block start */
666 jl = bptr->next->javalocals;
668 /* create a non-trappable rplpoint */
669 replace_create_replacement_point(jd, iinfo, rp++,
670 RPLPOINT_TYPE_BODY, iptr, &ra,
672 rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
675 case ICMD_INLINE_END:
676 assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
677 iinfo == iptr->sx.s23.s3.inlineinfo->parent);
678 iinfo = iptr->sx.s23.s3.inlineinfo;
680 if (iinfo->javalocals_end)
681 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
682 iinfo = iinfo->parent;
685 } /* end instruction loop */
686 } /* end basicblock loop */
688 assert((rp - rplpoints) == count);
689 assert((ra - regalloc) == alloccount);
691 /* store the data in the codeinfo */
693 code->rplpoints = rplpoints;
694 code->rplpointcount = count;
695 code->regalloc = regalloc;
696 code->regalloccount = alloccount;
697 code->globalcount = 0;
698 code->memuse = rd->memuse;
700 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
701 REPLACE_COUNT_INC(stat_regallocs, alloccount);
703 /* everything alright */
709 /* replace_free_replacement_points *********************************************
711 Free memory used by replacement points.
714 code.............codeinfo whose replacement points should be freed.
716 *******************************************************************************/
718 void replace_free_replacement_points(codeinfo *code)
723 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
726 MFREE(code->regalloc,rplalloc,code->regalloccount);
728 code->rplpoints = NULL;
729 code->rplpointcount = 0;
730 code->regalloc = NULL;
731 code->regalloccount = 0;
732 code->globalcount = 0;
736 /******************************************************************************/
737 /* PART II: Activating / deactivating replacement points */
738 /******************************************************************************/
741 /* replace_activate_replacement_points *****************************************
743 Activate the replacement points of the given compilation unit. When this
744 function returns, the replacement points are "armed", so each thread
745 reaching one of the points will enter the replacement mechanism.
748 code.............codeinfo of which replacement points should be
750 mappable.........if true, only mappable replacement points are
753 *******************************************************************************/
755 void replace_activate_replacement_points(codeinfo *code, bool mappable)
762 assert(code->savedmcode == NULL);
764 /* count trappable replacement points */
767 i = code->rplpointcount;
768 rp = code->rplpoints;
770 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
773 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
779 /* allocate buffer for saved machine code */
781 savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
782 code->savedmcode = savedmcode;
783 savedmcode += count * REPLACEMENT_PATCH_SIZE;
785 /* activate trappable replacement points */
786 /* (in reverse order to handle overlapping points within basic blocks) */
788 i = code->rplpointcount;
789 rp = code->rplpoints + i;
791 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
793 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
796 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
799 DOLOG( printf("activate replacement point:\n");
800 replace_replacement_point_println(rp, 1); fflush(stdout); );
802 savedmcode -= REPLACEMENT_PATCH_SIZE;
804 #if defined(ENABLE_JIT)
805 # if defined(ENABLE_DISASSEMBLER)
806 DOLOG( printf("\tinstruction before: ");
807 disassinstr(rp->pc); fflush(stdout); );
810 md_patch_replacement_point(rp->pc, savedmcode, false);
812 # if defined(ENABLE_DISASSEMBLER)
813 DOLOG( printf("\tinstruction after : ");
814 disassinstr(rp->pc); fflush(stdout); );
818 rp->flags |= RPLPOINT_FLAG_ACTIVE;
821 assert(savedmcode == code->savedmcode);
825 /* replace_deactivate_replacement_points ***************************************
827 Deactivate a replacement points in the given compilation unit.
828 When this function returns, the replacement points will be "un-armed",
829 that is a each thread reaching a point will just continue normally.
832 code.............the compilation unit
834 *******************************************************************************/
836 void replace_deactivate_replacement_points(codeinfo *code)
843 if (code->savedmcode == NULL) {
844 /* disarm countdown points by patching the branches */
846 i = code->rplpointcount;
847 rp = code->rplpoints;
849 if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
850 == RPLPOINT_FLAG_COUNTDOWN)
853 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
860 assert(code->savedmcode != NULL);
861 savedmcode = code->savedmcode;
863 /* de-activate each trappable replacement point */
865 i = code->rplpointcount;
866 rp = code->rplpoints;
869 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
874 DOLOG( printf("deactivate replacement point:\n");
875 replace_replacement_point_println(rp, 1); fflush(stdout); );
877 #if defined(ENABLE_JIT)
878 # if defined(ENABLE_DISASSEMBLER)
879 DOLOG( printf("\tinstruction before: ");
880 disassinstr(rp->pc); fflush(stdout); );
883 md_patch_replacement_point(rp->pc, savedmcode, true);
885 # if defined(ENABLE_DISASSEMBLER)
886 DOLOG( printf("\tinstruction before: ");
887 disassinstr(rp->pc); fflush(stdout); );
891 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
893 savedmcode += REPLACEMENT_PATCH_SIZE;
896 assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
898 /* free saved machine code */
900 MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
901 code->savedmcode = NULL;
905 /******************************************************************************/
906 /* PART III: The replacement mechanism */
907 /******************************************************************************/
910 /* replace_read_value **********************************************************
912 Read a value with the given allocation from the execution state.
915 es...............execution state
916 ra...............allocation
917 javaval..........where to put the value
920 *javaval.........the value
922 *******************************************************************************/
924 static void replace_read_value(executionstate_t *es,
926 replace_val_t *javaval)
928 if (ra->flags & INMEMORY) {
929 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
930 #ifdef HAS_4BYTE_STACKSLOT
931 if (IS_2_WORD_TYPE(ra->type)) {
932 javaval->l = *(u8*)(es->sp + ra->regoff);
936 javaval->p = *(ptrint*)(es->sp + ra->regoff);
937 #ifdef HAS_4BYTE_STACKSLOT
942 /* allocated register */
943 if (IS_FLT_DBL_TYPE(ra->type)) {
944 javaval->d = es->fltregs[ra->regoff];
946 if (ra->type == TYPE_FLT)
947 javaval->f = javaval->d;
949 #if defined(HAS_ADDRESS_REGISTER_FILE)
950 else if (IS_ADR_TYPE(ra->type)) {
951 javaval->p = es->adrregs[ra->regoff];
955 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
956 if (ra->type == TYPE_LNG) {
957 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
958 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
961 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
962 javaval->p = es->intregs[ra->regoff];
968 /* replace_write_value *********************************************************
970 Write a value to the given allocation in the execution state.
973 es...............execution state
974 ra...............allocation
975 *javaval.........the value
977 *******************************************************************************/
979 static void replace_write_value(executionstate_t *es,
981 replace_val_t *javaval)
983 if (ra->flags & INMEMORY) {
984 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
985 #ifdef HAS_4BYTE_STACKSLOT
986 if (IS_2_WORD_TYPE(ra->type)) {
987 *(u8*)(es->sp + ra->regoff) = javaval->l;
991 *(ptrint*)(es->sp + ra->regoff) = javaval->p;
992 #ifdef HAS_4BYTE_STACKSLOT
997 /* allocated register */
1000 es->fltregs[ra->regoff] = (double) javaval->f;
1003 es->fltregs[ra->regoff] = javaval->d;
1005 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1007 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1008 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1011 #if defined(HAS_ADDRESS_REGISTER_FILE)
1013 es->adrregs[ra->regoff] = javaval->p;
1016 es->intregs[ra->regoff] = javaval->p;
1022 /* replace_new_sourceframe *****************************************************
1024 Allocate a new source frame and insert it at the front of the frame list.
1027 ss...............the source state
1030 ss->frames.......set to new frame (the new head of the frame list).
1033 returns the new frame
1035 *******************************************************************************/
1037 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1039 sourceframe_t *frame;
1041 frame = (sourceframe_t*) DumpMemory::allocate(sizeof(sourceframe_t));
1042 MZERO(frame, sourceframe_t, 1);
1044 frame->down = ss->frames;
1051 /* replace_read_executionstate *************************************************
1053 Read a source frame from the given executions state.
1054 The new source frame is pushed to the front of the frame list of the
1058 rp...............replacement point at which `es` was taken
1059 es...............execution state
1060 ss...............the source state to add the source frame to
1061 topframe.........true, if the first (top-most) source frame on the
1065 *ss..............the source state with the newly created source frame
1068 *******************************************************************************/
1070 static s4 replace_normalize_type_map[] = {
1071 /* RPLPOINT_TYPE_STD |--> */ RPLPOINT_TYPE_STD,
1072 /* RPLPOINT_TYPE_EXH |--> */ RPLPOINT_TYPE_STD,
1073 /* RPLPOINT_TYPE_SBR |--> */ RPLPOINT_TYPE_STD,
1074 /* RPLPOINT_TYPE_CALL |--> */ RPLPOINT_TYPE_CALL,
1075 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1076 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1077 /* RPLPOINT_TYPE_BODY |--> */ RPLPOINT_TYPE_STD
1081 static void replace_read_executionstate(rplpoint *rp,
1082 executionstate_t *es,
1091 sourceframe_t *frame;
1094 stackslot_t *basesp;
1096 code = code_find_codeinfo_for_pc(rp->pc);
1098 topslot = TOP_IS_NORMAL;
1102 sp = (stackslot_t *) es->sp;
1104 /* in some cases the top stack slot is passed in REG_ITMP1 */
1106 if (rp->type == BBTYPE_EXH) {
1107 topslot = TOP_IS_IN_ITMP1;
1110 /* calculate base stack pointer */
1112 basesp = sp + code->stackframesize;
1114 /* create the source frame */
1116 frame = replace_new_sourceframe(ss);
1117 frame->method = rp->method;
1119 assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1120 frame->type = replace_normalize_type_map[rp->type];
1122 frame->fromcode = code;
1124 /* read local variables */
1126 count = m->maxlocals;
1127 frame->javalocalcount = count;
1128 frame->javalocals = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1129 frame->javalocaltype = (u1*) DumpMemory::allocate(sizeof(u1) * count);
1131 /* mark values as undefined */
1132 for (i=0; i<count; ++i) {
1133 #if !defined(NDEBUG)
1134 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1136 frame->javalocaltype[i] = TYPE_VOID;
1139 /* some entries in the intregs array are not meaningful */
1140 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1141 #if !defined(NDEBUG)
1142 es->intregs[REG_SP ] = (ptrint) 0x11dead1111dead11ULL;
1144 es->intregs[REG_PV ] = (ptrint) 0x11dead1111dead11ULL;
1146 #endif /* !defined(NDEBUG) */
1148 /* read javalocals */
1150 count = rp->regalloccount;
1153 while (count && (i = ra->index) >= 0) {
1154 assert(i < m->maxlocals);
1155 frame->javalocaltype[i] = ra->type;
1156 if (ra->type == TYPE_RET)
1157 frame->javalocals[i].i = ra->regoff;
1159 replace_read_value(es, ra, frame->javalocals + i);
1164 /* read instance, if this is the first rplpoint */
1166 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1167 if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1169 /* we are at the start of the method body, so if local 0 is set, */
1170 /* it is the instance. */
1171 if (frame->javalocaltype[0] == TYPE_ADR)
1172 frame->instance = frame->javalocals[0];
1177 md = rp->method->parseddesc;
1179 assert(md->paramcount >= 1);
1180 instra.type = TYPE_ADR;
1181 instra.regoff = md->params[0].regoff;
1182 if (md->params[0].inmemory) {
1183 instra.flags = INMEMORY;
1184 instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1189 replace_read_value(es, &instra, &(frame->instance));
1192 #if defined(__I386__)
1193 else if (!(rp->method->flags & ACC_STATIC)) {
1194 /* On i386 we always pass the first argument on stack. */
1195 frame->instance.a = *(java_object_t **)(basesp + 1);
1198 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1200 /* read stack slots */
1202 frame->javastackdepth = count;
1203 frame->javastack = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1204 frame->javastacktype = (u1*) DumpMemory::allocate(sizeof(u1) * count);
1206 #if !defined(NDEBUG)
1207 /* mark values as undefined */
1208 for (i=0; i<count; ++i) {
1209 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1210 frame->javastacktype[i] = TYPE_VOID;
1212 #endif /* !defined(NDEBUG) */
1216 /* the first stack slot is special in SBR and EXH blocks */
1218 if (topslot == TOP_IS_ON_STACK) {
1221 assert(ra->index == RPLALLOC_STACK);
1222 assert(ra->type == TYPE_ADR);
1223 frame->javastack[i].p = sp[-1];
1224 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1229 else if (topslot == TOP_IS_IN_ITMP1) {
1232 assert(ra->index == RPLALLOC_STACK);
1233 assert(ra->type == TYPE_ADR);
1234 frame->javastack[i].p = es->intregs[REG_ITMP1];
1235 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1240 else if (topslot == TOP_IS_VOID) {
1243 assert(ra->index == RPLALLOC_STACK);
1244 frame->javastack[i].l = 0;
1245 frame->javastacktype[i] = TYPE_VOID;
1251 /* read remaining stack slots */
1253 for (; count--; ra++) {
1254 if (ra->index == RPLALLOC_SYNC) {
1255 assert(rp->type == RPLPOINT_TYPE_INLINE);
1257 /* only read synchronization slots when traversing an inline point */
1260 sourceframe_t *calleeframe = frame->down;
1261 assert(calleeframe);
1262 assert(calleeframe->syncslotcount == 0);
1263 assert(calleeframe->syncslots == NULL);
1265 calleeframe->syncslotcount = 1;
1266 calleeframe->syncslots = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t));
1267 replace_read_value(es,ra,calleeframe->syncslots);
1270 frame->javastackdepth--;
1274 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1276 /* do not read parameters of calls down the call chain */
1278 if (!topframe && ra->index == RPLALLOC_PARAM) {
1279 frame->javastackdepth--;
1282 if (ra->type == TYPE_RET)
1283 frame->javastack[i].i = ra->regoff;
1285 replace_read_value(es,ra,frame->javastack + i);
1286 frame->javastacktype[i] = ra->type;
1293 /* replace_write_executionstate ************************************************
1295 Pop a source frame from the front of the frame list of the given source state
1296 and write its values into the execution state.
1299 rp...............replacement point for which execution state should be
1301 es...............the execution state to modify
1302 ss...............the given source state
1303 topframe.........true, if this is the last (top-most) source frame to be
1307 *es..............the execution state derived from the source state
1309 *******************************************************************************/
1311 static void replace_write_executionstate(rplpoint *rp,
1312 executionstate_t *es,
1321 sourceframe_t *frame;
1324 stackslot_t *basesp;
1326 code = code_find_codeinfo_for_pc(rp->pc);
1328 topslot = TOP_IS_NORMAL;
1330 /* pop a source frame */
1334 ss->frames = frame->down;
1336 /* calculate stack pointer */
1338 sp = (stackslot_t *) es->sp;
1340 basesp = sp + code->stackframesize;
1342 /* in some cases the top stack slot is passed in REG_ITMP1 */
1344 if (rp->type == BBTYPE_EXH) {
1345 topslot = TOP_IS_IN_ITMP1;
1348 /* write javalocals */
1351 count = rp->regalloccount;
1353 while (count && (i = ra->index) >= 0) {
1354 assert(i < m->maxlocals);
1355 assert(i < frame->javalocalcount);
1356 assert(ra->type == frame->javalocaltype[i]);
1357 if (ra->type == TYPE_RET) {
1358 /* XXX assert that it matches this rplpoint */
1361 replace_write_value(es, ra, frame->javalocals + i);
1366 /* write stack slots */
1370 /* the first stack slot is special in SBR and EXH blocks */
1372 if (topslot == TOP_IS_ON_STACK) {
1375 assert(ra->index == RPLALLOC_STACK);
1376 assert(i < frame->javastackdepth);
1377 assert(frame->javastacktype[i] == TYPE_ADR);
1378 sp[-1] = frame->javastack[i].p;
1383 else if (topslot == TOP_IS_IN_ITMP1) {
1386 assert(ra->index == RPLALLOC_STACK);
1387 assert(i < frame->javastackdepth);
1388 assert(frame->javastacktype[i] == TYPE_ADR);
1389 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1394 else if (topslot == TOP_IS_VOID) {
1397 assert(ra->index == RPLALLOC_STACK);
1398 assert(i < frame->javastackdepth);
1399 assert(frame->javastacktype[i] == TYPE_VOID);
1405 /* write remaining stack slots */
1407 for (; count--; ra++) {
1408 if (ra->index == RPLALLOC_SYNC) {
1409 assert(rp->type == RPLPOINT_TYPE_INLINE);
1411 /* only write synchronization slots when traversing an inline point */
1414 assert(frame->down);
1415 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1416 assert(frame->down->syncslots != NULL);
1418 replace_write_value(es,ra,frame->down->syncslots);
1423 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1425 /* do not write parameters of calls down the call chain */
1427 if (!topframe && ra->index == RPLALLOC_PARAM) {
1430 ra->index = RPLALLOC_PARAM;
1433 replace_write_value(es,ra,&v);
1437 assert(i < frame->javastackdepth);
1438 assert(ra->type == frame->javastacktype[i]);
1439 if (ra->type == TYPE_RET) {
1440 /* XXX assert that it matches this rplpoint */
1443 replace_write_value(es,ra,frame->javastack + i);
1455 /* md_push_stackframe **********************************************************
1457 Save the given return address, build the new stackframe,
1458 and store callee-saved registers.
1460 *** This function imitates the effects of a call and the ***
1461 *** method prolog of the callee. ***
1464 es...............execution state
1465 calleecode.......the code we are "calling"
1466 ra...............the return address to save
1469 *es..............the execution state after pushing the stack frame
1470 NOTE: es->pc, es->code, and es->pv are NOT updated.
1472 *******************************************************************************/
1474 void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra)
1478 stackslot_t *basesp;
1484 /* write the return address */
1486 #if STACKFRMAE_RA_BETWEEN_FRAMES
1487 es->sp -= SIZEOF_VOID_P;
1488 *((void **)es->sp) = (void *) ra;
1489 if (calleecode->stackframesize)
1490 es->sp -= (SIZE_OF_STACKSLOT - SIZEOF_VOID_P);
1491 #endif /* STACKFRAME_RA_BETWEEN_FRAMES */
1493 es->ra = (u1*) (ptrint) ra;
1495 /* build the stackframe */
1497 DOLOG( printf("building stackframe of %d words at %p\n",
1498 calleecode->stackframesize, (void*)es->sp); );
1500 sp = (stackslot_t *) es->sp;
1503 sp -= calleecode->stackframesize;
1506 /* in debug mode, invalidate stack frame first */
1508 /* XXX may not invalidate linkage area used by native code! */
1510 #if !defined(NDEBUG) && 0
1511 for (i=0; i< (basesp - sp) && i < 1; ++i) {
1512 sp[i] = 0xdeaddeadU;
1516 #if defined(__I386__)
1517 /* Stackslot 0 may contain the object instance for vftbl patching.
1518 Destroy it, so there's no undefined value used. */
1519 if ((basesp - sp) > 0) {
1524 /* save the return address register */
1526 #if STACKFRAME_RA_TOP_OF_FRAME
1527 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
1528 if (!code_is_leafmethod(calleecode))
1530 *--basesp = (ptrint) ra;
1531 #endif /* STACKFRAME_RA_TOP_OF_FRAME */
1533 #if STACKFRAME_RA_LINKAGE_AREA
1534 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
1535 if (!code_is_leafmethod(calleecode))
1537 *((uint8_t**) ((intptr_t) basesp + LA_LR_OFFSET)) = ra;
1538 #endif /* STACKFRAME_RA_LINKAGE_AREA */
1540 /* save int registers */
1543 for (i=0; i<calleecode->savedintcount; ++i) {
1544 while (nregdescint[--reg] != REG_SAV)
1547 *((uintptr_t*) basesp) = es->intregs[reg];
1549 /* XXX may not clobber saved regs used by native code! */
1550 #if !defined(NDEBUG) && 0
1551 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1555 /* save flt registers */
1559 for (i=0; i<calleecode->savedfltcount; ++i) {
1560 while (nregdescfloat[--reg] != REG_SAV)
1562 basesp -= STACK_SLOTS_PER_FLOAT;
1563 *((double*) basesp) = es->fltregs[reg];
1565 /* XXX may not clobber saved regs used by native code! */
1566 #if !defined(NDEBUG) && 0
1567 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1571 #if defined(HAS_ADDRESS_REGISTER_FILE)
1572 /* save adr registers */
1575 for (i=0; i<calleecode->savedadrcount; ++i) {
1576 while (nregdescadr[--reg] != REG_SAV)
1579 *((uintptr_t*) basesp) = es->adrregs[reg];
1581 /* XXX may not clobber saved regs used by native code! */
1582 #if !defined(NDEBUG) && 0
1583 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1590 /* replace_pop_activation_record ***********************************************
1592 Peel a stack frame from the execution state.
1594 *** This function imitates the effects of the method epilog ***
1595 *** and returning from the method call. ***
1598 es...............execution state
1599 frame............source frame, receives synchronization slots
1602 *es..............the execution state after popping the stack frame
1605 the return address of the poped activation record
1607 *******************************************************************************/
1609 u1* replace_pop_activation_record(executionstate_t *es,
1610 sourceframe_t *frame)
1621 /* calculate the base of the stack frame */
1623 sp = (stackslot_t *) es->sp;
1624 assert(frame->syncslotcount == 0);
1625 assert(frame->syncslots == NULL);
1626 count = code_get_sync_slot_count(es->code);
1627 frame->syncslotcount = count;
1628 frame->syncslots = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
1629 for (i=0; i<count; ++i) {
1630 frame->syncslots[i].p = *((intptr_t*) (sp + es->code->memuse + i)); /* XXX md_ function */
1633 /* pop the stackframe */
1635 executionstate_pop_stackframe(es);
1639 DOLOG( printf("RA = %p\n", (void*)ra); );
1641 /* Subtract one from the PC so we do not hit the replacement point */
1642 /* of the instruction following the call, if there is one. */
1646 /* find the new codeinfo */
1648 void* pv = md_codegen_get_pv_from_pc(ra);
1649 DOLOG( printf("PV = %p\n", pv); );
1651 code = code_get_codeinfo_for_pv(pv);
1652 DOLOG( printf("CODE = %p\n", (void*) code); );
1654 /* return NULL if we reached native code */
1656 es->pv = (uint8_t*) pv;
1659 return (code) ? ra : NULL;
1663 /* replace_patch_method_pointer ************************************************
1665 Patch a method pointer (may be in code, data segment, vftbl, or interface
1669 mpp..............address of the method pointer to patch
1670 entrypoint.......the new entrypoint of the method
1671 kind.............kind of call to patch, used only for debugging
1673 *******************************************************************************/
1675 static void replace_patch_method_pointer(methodptr *mpp,
1676 methodptr entrypoint,
1679 #if !defined(NDEBUG)
1684 DOLOG( printf("patch method pointer from: %p to %p\n",
1685 (void*) *mpp, (void*)entrypoint); );
1687 #if !defined(NDEBUG)
1688 oldcode = code_get_codeinfo_for_pv(*mpp);
1689 newcode = code_get_codeinfo_for_pv(entrypoint);
1691 DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1692 method_println(oldcode->m);
1693 printf("\t with %p ", (void*) newcode);
1694 method_println(newcode->m); );
1696 assert(oldcode->m == newcode->m);
1699 /* write the new entrypoint */
1701 *mpp = (methodptr) entrypoint;
1705 /* replace_patch_class *********************************************************
1707 Patch a method in the given class.
1710 vftbl............vftbl of the class
1711 m................the method to patch
1712 oldentrypoint....the old entrypoint to replace
1713 entrypoint.......the new entrypoint
1715 *******************************************************************************/
1717 void replace_patch_class(vftbl_t *vftbl,
1726 /* patch the vftbl of the class */
1728 replace_patch_method_pointer(vftbl->table + m->vftblindex,
1732 /* patch the interface tables */
1734 assert(oldentrypoint);
1736 for (i=0; i < vftbl->interfacetablelength; ++i) {
1737 mpp = vftbl->interfacetable[-i];
1738 mppend = mpp + vftbl->interfacevftbllength[i];
1739 for (; mpp != mppend; ++mpp)
1740 if (*mpp == oldentrypoint) {
1741 replace_patch_method_pointer(mpp, entrypoint, "interface");
1747 /* replace_patch_class_hierarchy ***********************************************
1749 Patch a method in all loaded classes.
1752 m................the method to patch
1753 oldentrypoint....the old entrypoint to replace
1754 entrypoint.......the new entrypoint
1756 *******************************************************************************/
1758 struct replace_patch_data_t {
1764 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1766 vftbl_t *vftbl = c->vftbl;
1769 && vftbl->vftbllength > pd->m->vftblindex
1770 && (void*) vftbl->table[pd->m->vftblindex] != (void*) (uintptr_t) &asm_abstractmethoderror
1771 && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
1773 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1777 void replace_patch_class_hierarchy(methodinfo *m,
1781 struct replace_patch_data_t pd;
1784 pd.oldentrypoint = oldentrypoint;
1785 pd.entrypoint = entrypoint;
1787 DOLOG_SHORT( printf("patching class hierarchy: ");
1788 method_println(m); );
1790 classcache_foreach_loaded_class(
1791 (classcache_foreach_functionptr_t) &replace_patch_callback,
1796 /* replace_patch_future_calls **************************************************
1798 Analyse a call site and depending on the kind of call patch the call, the
1799 virtual function table, or the interface table.
1802 ra...............return address pointing after the call site
1803 callerframe......source frame of the caller
1804 calleeframe......source frame of the callee, must have been mapped
1806 *******************************************************************************/
1808 void replace_patch_future_calls(u1 *ra,
1809 sourceframe_t *callerframe,
1810 sourceframe_t *calleeframe)
1813 methodptr entrypoint;
1814 methodptr oldentrypoint;
1817 codeinfo *calleecode;
1818 methodinfo *calleem;
1823 assert(callerframe->down == calleeframe);
1825 /* get the new codeinfo and the method that shall be entered */
1827 calleecode = calleeframe->tocode;
1830 calleem = calleeframe->method;
1831 assert(calleem == calleecode->m);
1833 entrypoint = (methodptr) calleecode->entrypoint;
1835 /* check if we are at an method entry rplpoint at the innermost frame */
1837 atentry = (calleeframe->down == NULL)
1838 && !(calleem->flags & ACC_STATIC)
1839 && (calleeframe->fromrp->id == 0); /* XXX */
1841 /* get the position to patch, in case it was a statically bound call */
1843 pv = callerframe->fromcode->entrypoint;
1844 patchpos = (u1*) md_jit_method_patch_address(pv, ra, NULL);
1846 if (patchpos == NULL) {
1847 /* the call was dispatched dynamically */
1849 /* we can only patch such calls if we are at the entry point */
1851 #if !defined(__I386__)
1852 /* On i386 we always know the instance argument. */
1857 assert((calleem->flags & ACC_STATIC) == 0);
1859 oldentrypoint = calleeframe->fromcode->entrypoint;
1861 /* we need to know the instance */
1863 if (!calleeframe->instance.a) {
1864 DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1865 replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1871 obj = calleeframe->instance.a;
1874 assert(vftbl->clazz->vftbl == vftbl);
1876 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->clazz); );
1878 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1881 /* the call was statically bound */
1883 #if defined(__I386__)
1884 /* It happens that there is a patcher trap. (pm) */
1885 if (*(u2 *)(patchpos - 1) == 0x0b0f) {
1888 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
1893 /* replace_push_activation_record **********************************************
1895 Push a stack frame onto the execution state.
1897 *** This function imitates the effects of a call and the ***
1898 *** method prolog of the callee. ***
1901 es...............execution state
1902 rpcall...........the replacement point at the call site
1903 callerframe......source frame of the caller, or NULL for creating the
1905 calleeframe......source frame of the callee, must have been mapped
1908 *es..............the execution state after pushing the stack frame
1910 *******************************************************************************/
1912 void replace_push_activation_record(executionstate_t *es,
1914 sourceframe_t *callerframe,
1915 sourceframe_t *calleeframe)
1921 codeinfo *calleecode;
1924 assert(!rpcall || callerframe);
1925 assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1926 assert(!rpcall || rpcall == callerframe->torp);
1927 assert(calleeframe);
1928 assert(!callerframe || calleeframe == callerframe->down);
1930 /* the compilation unit we are entering */
1932 calleecode = calleeframe->tocode;
1935 /* calculate the return address */
1938 ra = rpcall->pc + rpcall->callsize;
1940 ra = es->pc + 1 /* XXX this is ugly */;
1942 /* push the stackframe */
1944 md_push_stackframe(es, calleecode, ra);
1946 /* we move into a new code unit, set code, PC, PV */
1948 es->code = calleecode;
1949 es->pc = calleecode->entrypoint; /* XXX not needed? */
1950 es->pv = calleecode->entrypoint;
1952 /* write slots used for synchronization */
1954 sp = (stackslot_t *) es->sp;
1955 count = code_get_sync_slot_count(calleecode);
1956 assert(count == calleeframe->syncslotcount);
1957 for (i=0; i<count; ++i) {
1958 *((intptr_t*) (sp + calleecode->memuse + i)) = calleeframe->syncslots[i].p;
1961 /* redirect future invocations */
1963 if (callerframe && rpcall) {
1964 #if defined(REPLACE_PATCH_ALL)
1965 if (rpcall->type == callerframe->fromrp->type)
1967 if (rpcall == callerframe->fromrp)
1969 replace_patch_future_calls(ra, callerframe, calleeframe);
1974 /* replace_find_replacement_point **********************************************
1976 Find the replacement point in the given code corresponding to the
1977 position given in the source frame.
1980 code.............the codeinfo in which to search the rplpoint
1981 frame............the source frame defining the position to look for
1982 parent...........parent replacement point to match
1985 the replacement point
1987 *******************************************************************************/
1989 rplpoint * replace_find_replacement_point(codeinfo *code,
1990 sourceframe_t *frame,
2003 DOLOG( printf("searching replacement point for:\n");
2004 replace_source_frame_println(frame); );
2008 DOLOG( printf("code = %p\n", (void*)code); );
2010 rp = code->rplpoints;
2011 i = code->rplpointcount;
2013 if (rp->id == frame->id && rp->method == frame->method
2014 && rp->parent == parent
2015 && replace_normalize_type_map[rp->type] == frame->type)
2017 /* check if returnAddresses match */
2018 /* XXX optimize: only do this if JSRs in method */
2019 DOLOG( printf("checking match for:");
2020 replace_replacement_point_println(rp, 1); fflush(stdout); );
2023 for (j = rp->regalloccount; j--; ++ra) {
2024 if (ra->type == TYPE_RET) {
2025 if (ra->index == RPLALLOC_STACK) {
2026 assert(stacki < frame->javastackdepth);
2027 if (frame->javastack[stacki].i != ra->regoff)
2032 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2033 if (frame->javalocals[ra->index].i != ra->regoff)
2046 #if !defined(NDEBUG)
2047 printf("candidate replacement points were:\n");
2048 rp = code->rplpoints;
2049 i = code->rplpointcount;
2051 replace_replacement_point_println(rp, 1);
2055 vm_abort("no matching replacement point found");
2056 return NULL; /* NOT REACHED */
2060 /* replace_find_replacement_point_for_pc ***************************************
2062 Find the nearest replacement point at or before the given PC. The
2063 given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
2064 the replacement point to be found.
2067 code.............compilation unit the PC is in
2068 pc...............the machine code PC
2071 the replacement point found, or
2072 NULL if no replacement point was found
2074 *******************************************************************************/
2076 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc, unsigned desired_flags)
2082 DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
2083 method_println(code->m); );
2087 rp = code->rplpoints;
2088 for (i=0; i<code->rplpointcount; ++i, ++rp) {
2089 DOLOG( replace_replacement_point_println(rp, 2); );
2090 if (rp->pc <= pc && rp->pc + rp->callsize >= pc) {
2091 if (desired_flags) {
2092 if (rp->flags & desired_flags) {
2104 /* replace_pop_native_frame ****************************************************
2106 Unroll a native frame in the execution state and create a source frame
2110 es...............current execution state
2111 ss...............the current source state
2112 sfi..............stackframeinfo for the native frame
2115 es...............execution state after unrolling the native frame
2116 ss...............gets the added native source frame
2118 *******************************************************************************/
2120 static void replace_pop_native_frame(executionstate_t *es,
2122 stackframeinfo_t *sfi)
2124 sourceframe_t *frame;
2130 frame = replace_new_sourceframe(ss);
2134 /* remember pc and size of native frame */
2136 frame->nativepc = es->pc;
2137 frame->nativeframesize = (es->sp != 0) ? (((uintptr_t) sfi->sp) - ((uintptr_t) es->sp)) : 0;
2138 assert(frame->nativeframesize >= 0);
2140 /* remember values of saved registers */
2143 for (i=0; i<INT_REG_CNT; ++i) {
2144 if (nregdescint[i] == REG_SAV)
2145 frame->nativesavint[j++] = es->intregs[i];
2149 for (i=0; i<FLT_REG_CNT; ++i) {
2150 if (nregdescfloat[i] == REG_SAV)
2151 frame->nativesavflt[j++] = es->fltregs[i];
2154 #if defined(HAS_ADDRESS_REGISTER_FILE)
2156 for (i=0; i<ADR_REG_CNT; ++i) {
2157 if (nregdescadr[i] == REG_SAV)
2158 frame->nativesavadr[j++] = es->adrregs[i];
2162 /* restore saved registers */
2164 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2166 for (i=0; i<INT_REG_CNT; ++i) {
2167 if (nregdescint[i] == REG_SAV)
2168 es->intregs[i] = sfi->intregs[j++];
2171 /* XXX we don't have them, yet, in the sfi, so clear them */
2173 for (i=0; i<INT_REG_CNT; ++i) {
2174 if (nregdescint[i] == REG_SAV)
2179 /* XXX we don't have float registers in the sfi, so clear them */
2181 for (i=0; i<FLT_REG_CNT; ++i) {
2182 if (nregdescfloat[i] == REG_SAV)
2183 es->fltregs[i] = 0.0;
2186 #if defined(HAS_ADDRESS_REGISTER_FILE)
2187 # if defined(ENABLE_GC_CACAO)
2189 for (i=0; i<ADR_REG_CNT; ++i) {
2190 if (nregdescadr[i] == REG_SAV)
2191 es->adrregs[i] = sfi->adrregs[j++];
2194 for (i=0; i<ADR_REG_CNT; ++i) {
2195 if (nregdescadr[i] == REG_SAV)
2201 /* restore codeinfo of the native stub */
2203 code = code_get_codeinfo_for_pv(sfi->pv);
2205 /* restore sp, pv, pc and codeinfo of the parent method */
2207 es->sp = (uint8_t*) (((uintptr_t) sfi->sp) + md_stacktrace_get_framesize(code));
2208 #if STACKFRMAE_RA_BETWEEN_FRAMES
2209 es->sp += SIZEOF_VOID_P; /* skip return address */
2211 es->pv = (uint8_t*) md_codegen_get_pv_from_pc(sfi->ra);
2212 es->pc = (uint8_t*) (((uintptr_t) ((sfi->xpc) ? sfi->xpc : sfi->ra)) - 1);
2213 es->code = code_get_codeinfo_for_pv(es->pv);
2217 /* replace_push_native_frame ***************************************************
2219 Rebuild a native frame onto the execution state and remove its source frame.
2221 Note: The native frame is "rebuild" by setting fields like PC and stack
2222 pointer in the execution state accordingly. Values in the
2223 stackframeinfo may be modified, but the actual stack frame of the
2224 native code is not touched.
2227 es...............current execution state
2228 ss...............the current source state
2231 es...............execution state after re-rolling the native frame
2232 ss...............the native source frame is removed
2234 *******************************************************************************/
2236 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2238 sourceframe_t *frame;
2244 DOLOG( printf("pushing native frame\n"); );
2246 /* remove the frame from the source state */
2250 assert(REPLACE_IS_NATIVE_FRAME(frame));
2252 ss->frames = frame->down;
2254 /* skip sp for the native stub */
2256 es->sp -= md_stacktrace_get_framesize(frame->sfi->code);
2257 #if STACKFRMAE_RA_BETWEEN_FRAMES
2258 es->sp -= SIZEOF_VOID_P; /* skip return address */
2261 /* assert that the native frame has not moved */
2263 assert(es->sp == frame->sfi->sp);
2265 /* update saved registers in the stackframeinfo */
2267 #if defined(ENABLE_GC_CACAO)
2269 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2270 for (i=0; i<INT_REG_CNT; ++i) {
2271 if (nregdescint[i] == REG_SAV)
2272 frame->sfi->intregs[j++] = es->intregs[i];
2275 for (i=0; i<ADR_REG_CNT; ++i) {
2276 if (nregdescadr[i] == REG_SAV)
2277 frame->sfi->adrregs[j++] = es->adrregs[i];
2281 /* XXX leave float registers untouched here */
2284 /* restore saved registers */
2287 for (i=0; i<INT_REG_CNT; ++i) {
2288 if (nregdescint[i] == REG_SAV)
2289 es->intregs[i] = frame->nativesavint[j++];
2293 for (i=0; i<FLT_REG_CNT; ++i) {
2294 if (nregdescfloat[i] == REG_SAV)
2295 es->fltregs[i] = frame->nativesavflt[j++];
2298 #if defined(HAS_ADDRESS_REGISTER_FILE)
2300 for (i=0; i<ADR_REG_CNT; ++i) {
2301 if (nregdescadr[i] == REG_SAV)
2302 es->adrregs[i] = frame->nativesavadr[j++];
2306 /* skip the native frame on the machine stack */
2308 es->sp -= frame->nativeframesize;
2310 /* set the pc the next frame must return to */
2312 es->pc = frame->nativepc;
2316 /* replace_recover_source_state ************************************************
2318 Recover the source state from the given replacement point and execution
2322 rp...............replacement point that has been reached, if any
2323 sfi..............stackframeinfo, if called from native code
2324 es...............execution state at the replacement point rp
2329 *******************************************************************************/
2331 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2332 stackframeinfo_t *sfi,
2333 executionstate_t *es)
2338 #if defined(REPLACE_STATISTICS)
2342 /* create the source frame structure in dump memory */
2344 ss = (sourcestate_t*) DumpMemory::allocate(sizeof(sourcestate_t));
2347 /* each iteration of the loop recovers one source frame */
2354 DOLOG( executionstate_println(es); );
2356 /* if we are not at a replacement point, it is a native frame */
2359 DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2362 replace_pop_native_frame(es, ss, sfi);
2365 if (es->code == NULL)
2368 goto after_machine_frame;
2371 /* read the values for this source frame from the execution state */
2373 DOLOG( printf("recovering source state for%s:\n",
2374 (ss->frames == NULL) ? " TOPFRAME" : "");
2375 replace_replacement_point_println(rp, 1); );
2377 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2379 #if defined(ENABLE_VMLOG)
2380 vmlog_cacao_unrol_method(ss->frames->method);
2383 #if defined(REPLACE_STATISTICS)
2384 REPLACE_COUNT(stat_frames);
2386 replace_statistics_source_frame(ss->frames);
2389 /* in locked areas (below native frames), identity map the frame */
2392 ss->frames->torp = ss->frames->fromrp;
2393 ss->frames->tocode = ss->frames->fromcode;
2396 /* unroll to the next (outer) frame */
2399 /* this frame is in inlined code */
2401 DOLOG( printf("INLINED!\n"); );
2405 assert(rp->type == RPLPOINT_TYPE_INLINE);
2406 REPLACE_COUNT(stat_unroll_inline);
2409 /* this frame had been called at machine-level. pop it. */
2411 DOLOG( printf("UNWIND\n"); );
2413 ra = replace_pop_activation_record(es, ss->frames);
2415 DOLOG( printf("REACHED NATIVE CODE\n"); );
2419 #if !defined(ENABLE_GC_CACAO)
2420 break; /* XXX remove to activate native frames */
2425 /* find the replacement point at the call site */
2427 after_machine_frame:
2428 rp = replace_find_replacement_point_for_pc(es->code, es->pc, 0);
2431 vm_abort("could not find replacement point while unrolling call");
2433 DOLOG( printf("found replacement point.\n");
2434 replace_replacement_point_println(rp, 1); );
2436 assert(rp->type == RPLPOINT_TYPE_CALL);
2437 REPLACE_COUNT(stat_unroll_call);
2439 } /* end loop over source frames */
2441 REPLACE_COUNT_DIST(stat_dist_frames, depth);
2447 /* replace_map_source_state ****************************************************
2449 Map each source frame in the given source state to a target replacement
2450 point and compilation unit. If no valid code is available for a source
2451 frame, it is (re)compiled.
2454 ss...............the source state
2457 ss...............the source state, modified: The `torp` and `tocode`
2458 fields of each source frame are set.
2461 true.............everything went ok
2462 false............an exception has been thrown
2464 *******************************************************************************/
2466 static bool replace_map_source_state(sourcestate_t *ss)
2468 sourceframe_t *frame;
2471 rplpoint *parent; /* parent of inlined rplpoint */
2472 #if defined(REPLACE_STATISTICS)
2479 /* iterate over the source frames from outermost to innermost */
2481 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2483 /* XXX skip native frames */
2485 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2490 /* map frames which are not already mapped */
2492 if (frame->tocode) {
2493 code = frame->tocode;
2498 assert(frame->torp == NULL);
2500 if (parent == NULL) {
2501 /* find code for this frame */
2503 #if defined(REPLACE_STATISTICS)
2504 oldcode = frame->method->code;
2506 /* request optimization of hot methods and their callers */
2508 if (frame->method->hitcountdown < 0
2509 || (frame->down && frame->down->method->hitcountdown < 0))
2510 jit_request_optimization(frame->method);
2512 code = jit_get_current_code(frame->method);
2515 return false; /* exception */
2517 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2522 /* map this frame */
2524 rp = replace_find_replacement_point(code, frame, parent);
2526 frame->tocode = code;
2530 if (rp->type == RPLPOINT_TYPE_CALL) {
2543 /* replace_map_source_state_identity *******************************************
2545 Map each source frame in the given source state to the same replacement
2546 point and compilation unit it was derived from. This is mainly used for
2550 ss...............the source state
2553 ss...............the source state, modified: The `torp` and `tocode`
2554 fields of each source frame are set.
2556 *******************************************************************************/
2558 #if defined(ENABLE_GC_CACAO)
2559 static void replace_map_source_state_identity(sourcestate_t *ss)
2561 sourceframe_t *frame;
2563 /* iterate over the source frames from outermost to innermost */
2565 for (frame = ss->frames; frame != NULL; frame = frame->down) {
2567 /* skip native frames */
2569 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2573 /* map frames using the identity mapping */
2575 if (frame->tocode) {
2576 assert(frame->tocode == frame->fromcode);
2577 assert(frame->torp == frame->fromrp);
2579 assert(frame->tocode == NULL);
2580 assert(frame->torp == NULL);
2581 frame->tocode = frame->fromcode;
2582 frame->torp = frame->fromrp;
2589 /* replace_build_execution_state ***********************************************
2591 Build an execution state for the given (mapped) source state.
2593 !!! CAUTION: This function rewrites the machine stack !!!
2595 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2598 ss...............the source state. Must have been mapped by
2599 replace_map_source_state before.
2600 es...............the base execution state on which to build
2603 *es..............the new execution state
2605 *******************************************************************************/
2607 static void replace_build_execution_state(sourcestate_t *ss,
2608 executionstate_t *es)
2611 sourceframe_t *prevframe;
2618 while (ss->frames) {
2620 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2621 prevframe = ss->frames;
2622 replace_push_native_frame(es, ss);
2628 if (parent == NULL) {
2629 /* create a machine-level stack frame */
2631 DOLOG( printf("pushing activation record for:\n");
2632 if (rp) replace_replacement_point_println(rp, 1);
2633 else printf("\tfirst frame\n"); );
2635 replace_push_activation_record(es, rp, prevframe, ss->frames);
2637 DOLOG( executionstate_println(es); );
2640 rp = ss->frames->torp;
2643 DOLOG( printf("creating execution state for%s:\n",
2644 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2645 replace_replacement_point_println(ss->frames->fromrp, 1);
2646 replace_replacement_point_println(rp, 1); );
2648 es->code = ss->frames->tocode;
2649 prevframe = ss->frames;
2651 #if defined(ENABLE_VMLOG)
2652 vmlog_cacao_rerol_method(ss->frames->method);
2655 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2657 DOLOG( executionstate_println(es); );
2659 if (rp->type == RPLPOINT_TYPE_CALL) {
2670 /* replace_me ******************************************************************
2672 This function is called by the signal handler when a thread reaches
2673 a replacement point. `replace_me` must map the execution state to the
2674 target replacement point and let execution continue there.
2676 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2679 rp...............replacement point that has been reached
2680 es...............execution state read by signal handler
2682 *******************************************************************************/
2684 static void replace_me(rplpoint *rp, executionstate_t *es)
2686 stackframeinfo_t *sfi;
2688 sourceframe_t *frame;
2691 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2692 threadobject *thread;
2695 origcode = es->code;
2698 #if defined(ENABLE_TLH)
2699 /*printf("Replacing in %s/%s\n", rp->method->clazz->name->text, rp->method->name->text);*/
2702 /*if (strcmp(rp->method->clazz->name->text, "antlr/AlternativeElement") == 0 && strcmp(rp->method->name->text, "getAutoGenType") ==0) opt_TraceReplacement = 2; else opt_TraceReplacement = 0;*/
2704 DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2705 stat_replacements, (void*)THREADOBJECT,
2707 method_println(es->code->m); );
2709 DOLOG( replace_replacement_point_println(rp, 1); );
2711 REPLACE_COUNT(stat_replacements);
2713 // Create new dump memory area.
2716 /* Get the stackframeinfo for the current thread. */
2718 sfi = threads_get_current_stackframeinfo();
2720 /* recover source state */
2722 ss = replace_recover_source_state(rp, sfi, es);
2724 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2725 /* if there is a collection pending, we assume the replacement point should
2726 suspend this thread */
2730 thread = THREADOBJECT;
2732 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2734 /* map the sourcestate using the identity mapping */
2735 replace_map_source_state_identity(ss);
2737 /* since we enter the same method again, we turn off rps now */
2738 /* XXX michi: can we really do this? what if the rp was active before
2739 we activated it for the gc? */
2740 replace_deactivate_replacement_points(origcode);
2742 /* remember executionstate and sourcestate for this thread */
2743 GC_EXECUTIONSTATE = es;
2744 GC_SOURCESTATE = ss;
2746 /* really suspend this thread now (PC = 0) */
2747 threads_suspend_ack(NULL, NULL);
2749 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2752 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2754 /* map the source state */
2756 if (!replace_map_source_state(ss))
2757 vm_abort("exception during method replacement");
2759 DOLOG( replace_sourcestate_println(ss); );
2761 DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2763 #if !defined(NDEBUG)
2764 /* avoid infinite loops by self-replacement, only if not in testing mode */
2766 if (!opt_TestReplacement) {
2769 frame = frame->down;
2771 if (frame->torp == origrp) {
2773 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2775 replace_deactivate_replacement_points(origcode);
2780 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2784 /* build the new execution state */
2786 replace_build_execution_state(ss, es);
2788 #if !defined(NDEBUG)
2789 /* continue execution after patched machine code, if testing mode enabled */
2791 if (opt_TestReplacement)
2792 es->pc += REPLACEMENT_PATCH_SIZE;
2797 /* replace_handler *************************************************************
2799 This function is called by the signal handler. It determines if there
2800 is an active replacement point pending at the given PC and returns
2803 THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2806 pc...............the program counter that triggered the replacement.
2807 es...............the execution state (machine state) to which the
2808 replacement should be applied.
2811 es...............the execution state after replacement finished.
2814 true.............replacement done, everything went ok
2815 false............no replacement done, execution state unchanged
2817 *******************************************************************************/
2819 bool replace_handler(u1 *pc, executionstate_t *es)
2823 #if defined(ENABLE_RT_TIMING)
2824 struct timespec time_start, time_end;
2827 /* search the codeinfo for the given PC */
2829 code = code_find_codeinfo_for_pc(pc);
2832 /* search for a replacement point at the given PC */
2834 rp = replace_find_replacement_point_for_pc(code, pc, (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN));
2836 /* check if the replacement point belongs to given PC and is active */
2838 if ((rp != NULL) && (rp->pc == pc)
2839 && (rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))) {
2841 DOLOG( printf("valid replacement point\n"); );
2843 /* set codeinfo pointer in execution state */
2847 /* do the actual replacement */
2849 #if defined(ENABLE_RT_TIMING)
2850 RT_TIMING_GET_TIME(time_start);
2855 #if defined(ENABLE_RT_TIMING)
2856 RT_TIMING_GET_TIME(time_end);
2857 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_REPLACE);
2860 /* new code is entered after returning */
2862 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2870 /******************************************************************************/
2871 /* NOTE: Stuff specific to the exact GC is below. */
2872 /******************************************************************************/
2874 #if defined(ENABLE_GC_CACAO)
2875 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
2877 stackframeinfo_t *sfi;
2878 executionstate_t *es;
2881 /* Get the stackframeinfo of this thread. */
2883 assert(thread == THREADOBJECT);
2885 sfi = threads_get_current_stackframeinfo();
2887 /* create the execution state */
2888 es = (executionstate_t*) DumpMemory::allocate(sizeof(executionstate_t));
2891 es->pv = 0; /* since we are in a native, PV is invalid! */
2892 es->code = NULL; /* since we are in a native, we do not have a codeinfo */
2894 /* we assume we are in a native (no replacement point)! */
2895 ss = replace_recover_source_state(NULL, sfi, es);
2897 /* map the sourcestate using the identity mapping */
2898 replace_map_source_state_identity(ss);
2900 /* remember executionstate and sourcestate for this thread */
2901 GC_EXECUTIONSTATE = es;
2902 GC_SOURCESTATE = ss;
2906 #if defined(ENABLE_GC_CACAO)
2907 void replace_gc_into_native(threadobject *thread)
2909 executionstate_t *es;
2912 /* get the executionstate and sourcestate for the given thread */
2913 es = GC_EXECUTIONSTATE;
2914 ss = GC_SOURCESTATE;
2916 /* rebuild the stack of the given thread */
2917 replace_build_execution_state(ss, es);
2922 /******************************************************************************/
2923 /* NOTE: No important code below. */
2924 /******************************************************************************/
2927 /* statistics *****************************************************************/
2929 #if defined(REPLACE_STATISTICS)
2930 static void print_freq(FILE *file,int *array,int limit)
2935 for (i=0; i<limit; ++i)
2937 sum += array[limit];
2938 for (i=0; i<limit; ++i) {
2940 fprintf(file," %3d: %8d (cum %3d%%)\n",
2941 i, array[i], (sum) ? ((100*cum)/sum) : 0);
2943 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
2945 #endif /* defined(REPLACE_STATISTICS) */
2948 #if defined(REPLACE_STATISTICS)
2950 #define REPLACE_PRINT_DIST(name, array) \
2951 printf(" " name " distribution:\n"); \
2952 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
2954 void replace_print_statistics(void)
2956 printf("replacement statistics:\n");
2957 printf(" # of replacements: %d\n", stat_replacements);
2958 printf(" # of frames: %d\n", stat_frames);
2959 printf(" # of recompilations: %d\n", stat_recompile);
2960 printf(" patched static calls:%d\n", stat_staticpatch);
2961 printf(" unrolled inlines: %d\n", stat_unroll_inline);
2962 printf(" unrolled calls: %d\n", stat_unroll_call);
2963 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
2964 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
2965 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
2966 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
2967 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
2968 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
2969 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
2970 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
2971 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
2972 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
2974 printf(" # of methods: %d\n", stat_methods);
2975 printf(" # of replacement points: %d\n", stat_rploints);
2976 printf(" # of regallocs: %d\n", stat_regallocs);
2977 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
2978 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
2979 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
2983 #endif /* defined(REPLACE_STATISTICS) */
2986 #if defined(REPLACE_STATISTICS)
2987 static void replace_statistics_source_frame(sourceframe_t *frame)
2996 for (i=0; i<frame->javalocalcount; ++i) {
2997 switch (frame->javalocaltype[i]) {
2998 case TYPE_ADR: adr++; break;
2999 case TYPE_RET: ret++; break;
3000 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3001 case TYPE_VOID: vd++; break;
3006 REPLACE_COUNT_DIST(stat_dist_locals, n);
3007 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3008 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3009 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3010 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3011 adr = ret = prim = n = 0;
3012 for (i=0; i<frame->javastackdepth; ++i) {
3013 switch (frame->javastacktype[i]) {
3014 case TYPE_ADR: adr++; break;
3015 case TYPE_RET: ret++; break;
3016 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3020 REPLACE_COUNT_DIST(stat_dist_stack, n);
3021 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3022 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3023 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3025 #endif /* defined(REPLACE_STATISTICS) */
3028 /* debugging helpers **********************************************************/
3030 /* replace_replacement_point_println *******************************************
3032 Print replacement point info.
3035 rp...............the replacement point to print
3037 *******************************************************************************/
3039 #if !defined(NDEBUG)
3041 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3043 static const char *replace_type_str[] = {
3053 void replace_replacement_point_println(rplpoint *rp, int depth)
3059 printf("(rplpoint *)NULL\n");
3063 for (j=0; j<depth; ++j)
3066 printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3067 rp->id, (void*)rp,rp->pc,rp->callsize,
3068 replace_type_str[rp->type]);
3069 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3071 if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3072 printf(" COUNTDOWN");
3073 if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3075 printf(" parent:%p\n", (void*)rp->parent);
3076 for (j=0; j<depth; ++j)
3078 printf("ra:%d = [", rp->regalloccount);
3080 for (j=0; j<rp->regalloccount; ++j) {
3083 index = rp->regalloc[j].index;
3085 case RPLALLOC_STACK: printf("S"); break;
3086 case RPLALLOC_PARAM: printf("P"); break;
3087 case RPLALLOC_SYNC : printf("Y"); break;
3088 default: printf("%d", index);
3090 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3091 if (rp->regalloc[j].type == TYPE_RET) {
3092 printf("ret(L%03d)", rp->regalloc[j].regoff);
3095 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3100 for (j=0; j<depth; ++j)
3103 method_print(rp->method);
3107 #endif /* !defined(NDEBUG) */
3110 /* replace_show_replacement_points *********************************************
3112 Print replacement point info.
3115 code.............codeinfo whose replacement points should be printed.
3117 *******************************************************************************/
3119 #if !defined(NDEBUG)
3120 void replace_show_replacement_points(codeinfo *code)
3128 printf("(codeinfo *)NULL\n");
3132 printf("\treplacement points: %d\n",code->rplpointcount);
3134 printf("\ttotal allocations : %d\n",code->regalloccount);
3135 printf("\tsaved int regs : %d\n",code->savedintcount);
3136 printf("\tsaved flt regs : %d\n",code->savedfltcount);
3137 #if defined(HAS_ADDRESS_REGISTER_FILE)
3138 printf("\tsaved adr regs : %d\n",code->savedadrcount);
3140 printf("\tmemuse : %d\n",code->memuse);
3144 for (i=0; i<code->rplpointcount; ++i) {
3145 rp = code->rplpoints + i;
3148 parent = rp->parent;
3151 parent = parent->parent;
3153 replace_replacement_point_println(rp, depth);
3159 #if !defined(NDEBUG)
3160 static void java_value_print(s4 type, replace_val_t value)
3165 printf("%016llx",(unsigned long long) value.l);
3167 if (type < 0 || type > TYPE_RET)
3168 printf(" <INVALID TYPE:%d>", type);
3170 printf(" %s", show_jit_type_names[type]);
3172 if (type == TYPE_ADR && value.a != NULL) {
3175 utf_display_printable_ascii_classname(obj->vftbl->clazz->name);
3177 if (obj->vftbl->clazz == class_java_lang_String) {
3179 u = javastring_toutf(obj, false);
3180 utf_display_printable_ascii(u);
3184 else if (type == TYPE_INT) {
3185 printf(" %ld", (long) value.i);
3187 else if (type == TYPE_LNG) {
3188 printf(" %lld", (long long) value.l);
3190 else if (type == TYPE_FLT) {
3191 printf(" %f", value.f);
3193 else if (type == TYPE_DBL) {
3194 printf(" %f", value.d);
3197 #endif /* !defined(NDEBUG) */
3200 #if !defined(NDEBUG)
3201 void replace_source_frame_println(sourceframe_t *frame)
3206 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3207 printf("\tNATIVE\n");
3208 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3209 printf("\tnativepc: %p\n", frame->nativepc);
3210 printf("\tframesize: %d\n", frame->nativeframesize);
3213 for (i=0; i<INT_REG_CNT; ++i) {
3214 if (nregdescint[i] == REG_SAV)
3215 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3219 for (i=0; i<FLT_REG_CNT; ++i) {
3220 if (nregdescfloat[i] == REG_SAV)
3221 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3229 method_println(frame->method);
3230 printf("\tid: %d\n", frame->id);
3231 printf("\ttype: %s\n", replace_type_str[frame->type]);
3234 if (frame->instance.a) {
3235 printf("\tinstance: ");
3236 java_value_print(TYPE_ADR, frame->instance);
3240 if (frame->javalocalcount) {
3241 printf("\tlocals (%d):\n",frame->javalocalcount);
3242 for (i=0; i<frame->javalocalcount; ++i) {
3243 t = frame->javalocaltype[i];
3244 if (t == TYPE_VOID) {
3245 printf("\tlocal[ %2d] = void\n",i);
3248 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3249 java_value_print(t, frame->javalocals[i]);
3256 if (frame->javastackdepth) {
3257 printf("\tstack (depth %d):\n",frame->javastackdepth);
3258 for (i=0; i<frame->javastackdepth; ++i) {
3259 t = frame->javastacktype[i];
3260 if (t == TYPE_VOID) {
3261 printf("\tstack[%2d] = void", i);
3264 printf("\tstack[%2d] = ",i);
3265 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3272 if (frame->syncslotcount) {
3273 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3274 for (i=0; i<frame->syncslotcount; ++i) {
3275 printf("\tslot[%2d] = %016llx\n",i,(unsigned long long) frame->syncslots[i].p);
3280 if (frame->fromcode) {
3281 printf("\tfrom %p ", (void*)frame->fromcode);
3282 method_println(frame->fromcode->m);
3284 if (frame->tocode) {
3285 printf("\tto %p ", (void*)frame->tocode);
3286 method_println(frame->tocode->m);
3289 if (frame->fromrp) {
3290 printf("\tfrom replacement point:\n");
3291 replace_replacement_point_println(frame->fromrp, 2);
3294 printf("\tto replacement point:\n");
3295 replace_replacement_point_println(frame->torp, 2);
3300 #endif /* !defined(NDEBUG) */
3303 /* replace_sourcestate_println *************************************************
3308 ss...............the source state to print
3310 *******************************************************************************/
3312 #if !defined(NDEBUG)
3313 void replace_sourcestate_println(sourcestate_t *ss)
3316 sourceframe_t *frame;
3319 printf("(sourcestate_t *)NULL\n");
3323 printf("sourcestate_t:\n");
3325 for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3326 printf(" frame %d:\n", i);
3327 replace_source_frame_println(frame);
3333 /* replace_sourcestate_println_short *******************************************
3335 Print a compact representation of the given source state.
3338 ss...............the source state to print
3340 *******************************************************************************/
3342 #if !defined(NDEBUG)
3343 void replace_sourcestate_println_short(sourcestate_t *ss)
3345 sourceframe_t *frame;
3347 for (frame = ss->frames; frame != NULL; frame = frame->down) {
3350 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3351 printf("NATIVE (pc %p size %d) ",
3352 (void*)frame->nativepc, frame->nativeframesize);
3353 replace_stackframeinfo_println(frame->sfi);
3358 printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3361 printf("%s", replace_type_str[frame->fromrp->type]);
3363 if (frame->torp && frame->torp->type != frame->fromrp->type)
3364 printf("->%s", replace_type_str[frame->torp->type]);
3366 if (frame->tocode != frame->fromcode)
3367 printf(" (%p->%p/%d) ",
3368 (void*) frame->fromcode, (void*) frame->tocode,
3371 printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3373 method_println(frame->method);
3378 #if !defined(NDEBUG)
3379 static void replace_stackframeinfo_println(stackframeinfo_t *sfi)
3381 printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3382 (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3383 (void*)sfi->ra, (void*)sfi->xpc);
3386 method_println(sfi->code->m);
3394 * These are local overrides for various environment variables in Emacs.
3395 * Please do not remove this and leave it at the end of the file, where
3396 * Emacs will automagically detect them.
3397 * ---------------------------------------------------------------------
3400 * indent-tabs-mode: t
3404 * vim:noexpandtab:sw=4:ts=4: