1 /* vm/jit/replace.c - on-stack replacement of methods
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Edwin Steiner
43 #include "mm/memory.h"
44 #include "toolbox/logging.h"
45 #include "vm/options.h"
46 #include "vm/stringlocal.h"
47 #include "vm/jit/abi.h"
48 #include "vm/jit/jit.h"
49 #include "vm/jit/replace.h"
50 #include "vm/jit/asmpart.h"
51 #include "vm/jit/disass.h"
52 #include "vm/jit/show.h"
53 #include "vm/jit/methodheader.h"
55 #include "native/include/java_lang_String.h"
58 /*** configuration of native stack slot size **********************************/
60 /* XXX this should be in md-abi.h files, probably */
62 #if defined(HAS_4BYTE_STACKSLOT)
63 #define SIZE_OF_STACKSLOT 4
64 #define STACK_SLOTS_PER_FLOAT 2
65 typedef u4 stackslot_t;
67 #define SIZE_OF_STACKSLOT 8
68 #define STACK_SLOTS_PER_FLOAT 1
69 typedef u8 stackslot_t;
73 /*** debugging ****************************************************************/
75 /*#define REPLACE_VERBOSE*/
77 #if !defined(NDEBUG) && defined(REPLACE_VERBOSE)
78 #define DOLOG(code) do{ if (1) { code; } } while(0)
84 /*** debugging ****************************************************************/
86 #define REPLACE_STATISTICS
88 #if defined(REPLACE_STATISTICS)
90 static int stat_replacements = 0;
91 static int stat_frames = 0;
92 static int stat_recompile = 0;
93 static int stat_unroll_inline = 0;
94 static int stat_unroll_call = 0;
95 static int stat_dist_frames[20] = { 0 };
96 static int stat_dist_locals[20] = { 0 };
97 static int stat_dist_locals_adr[10] = { 0 };
98 static int stat_dist_locals_prim[10] = { 0 };
99 static int stat_dist_locals_ret[10] = { 0 };
100 static int stat_dist_locals_void[10] = { 0 };
101 static int stat_dist_stack[10] = { 0 };
102 static int stat_dist_stack_adr[10] = { 0 };
103 static int stat_dist_stack_prim[10] = { 0 };
104 static int stat_dist_stack_ret[10] = { 0 };
105 static int stat_methods = 0;
106 static int stat_rploints = 0;
107 static int stat_regallocs = 0;
108 static int stat_dist_method_rplpoints[20] = { 0 };
110 #define REPLACE_COUNT(cnt) (cnt)++
111 #define REPLACE_COUNT_INC(cnt, inc) ((cnt) += (inc))
113 #define REPLACE_COUNT_DIST(array, val) \
115 int limit = (sizeof(array) / sizeof(int)) - 1; \
116 if ((val) < (limit)) (array)[val]++; \
117 else (array)[limit]++; \
120 #define REPLACE_PRINT_DIST(name, array) \
121 printf(" " name " distribution:\n"); \
122 print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
124 static void print_freq(FILE *file,int *array,int limit)
129 for (i=0; i<limit; ++i)
132 for (i=0; i<limit; ++i) {
134 fprintf(file," %3d: %8d (cum %3d%%)\n",
135 i, array[i], (sum) ? ((100*cum)/sum) : 0);
137 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
140 void replace_print_statistics(void)
142 printf("replacement statistics:\n");
143 printf(" # of replacements: %d\n", stat_replacements);
144 printf(" # of frames: %d\n", stat_frames);
145 printf(" # of recompilations: %d\n", stat_recompile);
146 printf(" unrolled inlines: %d\n", stat_unroll_inline);
147 printf(" unrolled calls: %d\n", stat_unroll_call);
148 REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
149 REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
150 REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
151 REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
152 REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
153 REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
154 REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
155 REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
156 REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
157 REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
159 printf(" # of methods: %d\n", stat_methods);
160 printf(" # of replacement points: %d\n", stat_rploints);
161 printf(" # of regallocs: %d\n", stat_regallocs);
162 printf(" per rplpoint: %f\n", (double)stat_regallocs / stat_rploints);
163 printf(" per method: %f\n", (double)stat_regallocs / stat_methods);
164 REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
171 #define REPLACE_COUNT(cnt)
172 #define REPLACE_COUNT_INC(cnt, inc)
173 #define REPLACE_COUNT_DIST(array, val)
175 #endif /* defined(REPLACE_STATISTICS) */
177 /*** constants used internally ************************************************/
179 #define TOP_IS_NORMAL 0
180 #define TOP_IS_ON_STACK 1
181 #define TOP_IS_IN_ITMP1 2
182 #define TOP_IS_VOID 3
185 /* replace_create_replacement_point ********************************************
187 Create a replacement point.
190 jd...............current jitdata
191 iinfo............inlining info for the current position
192 rp...............pre-allocated (uninitialized) rplpoint
193 type.............RPLPOINT_TYPE constant
194 *pra.............current rplalloc pointer
195 javalocals.......the javalocals at the current point
196 stackvars........the stack variables at the current point
197 stackdepth.......the stack depth at the current point
198 paramcount.......number of parameters at the start of stackvars
201 *rpa.............points to the next free rplalloc
203 *******************************************************************************/
205 static void replace_create_replacement_point(jitdata *jd,
206 insinfo_inline *iinfo,
223 REPLACE_COUNT(stat_rploints);
225 rp->method = (iinfo) ? iinfo->method : jd->m;
226 rp->pc = NULL; /* set by codegen */
227 rp->outcode = NULL; /* set by codegen */
228 rp->callsize = 0; /* set by codegen */
233 rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
235 /* XXX unify these two fields */
237 rp->parent = (iinfo) ? iinfo->rp : NULL;
239 /* store local allocation info of javalocals */
242 for (i = 0; i < rp->method->maxlocals; ++i) {
243 index = javalocals[i];
248 if (index < UNUSED) {
249 ra->regoff = (UNUSED - index) - 1;
255 ra->flags = v->flags & (INMEMORY);
256 ra->regoff = v->vv.regoff;
263 /* store allocation info of java stack vars */
265 for (i = 0; i < stackdepth; ++i) {
266 v = VAR(stackvars[i]);
267 ra->flags = v->flags & (INMEMORY);
268 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
270 /* XXX how to handle locals on the stack containing returnAddresses? */
271 if (v->type == TYPE_RET) {
272 assert(stackvars[i] >= jd->localcount);
273 ra->regoff = v->vv.retaddr->nr;
276 ra->regoff = v->vv.regoff;
280 /* total number of allocations */
282 rp->regalloccount = ra - rp->regalloc;
288 /* replace_create_replacement_points *******************************************
290 Create the replacement points for the given code.
293 jd...............current jitdata, must not have any replacement points
296 code->rplpoints.......set to the list of replacement points
297 code->rplpointcount...number of replacement points
298 code->regalloc........list of allocation info
299 code->regalloccount...total length of allocation info list
300 code->globalcount.....number of global allocations at the
301 start of code->regalloc
304 true.............everything ok
305 false............an exception has been thrown
307 *******************************************************************************/
309 bool replace_create_replacement_points(jitdata *jd)
327 insinfo_inline *iinfo;
328 insinfo_inline *calleeinfo;
331 REPLACE_COUNT(stat_methods);
333 /* get required compiler data */
338 /* assert that we wont overwrite already allocated data */
342 assert(code->rplpoints == NULL);
343 assert(code->rplpointcount == 0);
344 assert(code->regalloc == NULL);
345 assert(code->regalloccount == 0);
346 assert(code->globalcount == 0);
348 /* iterate over the basic block list to find replacement points */
355 javalocals = DMNEW(s4, jd->maxlocals);
357 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
361 if (bptr->flags < BBFINISHED)
364 /* get info about this block */
367 iinfo = bptr->inlineinfo;
369 /* initialize javalocals at the start of this block */
371 if (bptr->javalocals)
372 MCOPY(javalocals, bptr->javalocals, s4, m->maxlocals);
374 for (i=0; i<m->maxlocals; ++i)
375 javalocals[i] = UNUSED;
377 /* iterate over the instructions */
380 iend = iptr + bptr->icount;
383 for (; iptr != iend; ++iptr) {
385 case ICMD_INVOKESTATIC:
386 case ICMD_INVOKESPECIAL:
387 case ICMD_INVOKEVIRTUAL:
388 case ICMD_INVOKEINTERFACE:
389 INSTRUCTION_GET_METHODDESC(iptr, md);
391 for (i=0; i<m->maxlocals; ++i)
392 if (javalocals[i] != UNUSED)
394 alloccount += iptr->s1.argcount;
396 alloccount -= iinfo->throughcount;
404 /* XXX share code with stack.c */
405 j = iptr->dst.varindex;
406 i = iptr->sx.s23.s3.javaindex;
408 if (iptr->flags.bits & INS_FLAG_RETADDR)
409 javalocals[i] = iptr->sx.s23.s2.retaddrnr;
412 if (iptr->flags.bits & INS_FLAG_KILL_PREV)
413 javalocals[i-1] = UNUSED;
414 if (iptr->flags.bits & INS_FLAG_KILL_NEXT)
415 javalocals[i+1] = UNUSED;
430 case ICMD_INLINE_START:
431 iinfo = iptr->sx.s23.s3.inlineinfo;
434 for (i=0; i<m->maxlocals; ++i)
435 if (javalocals[i] != UNUSED)
437 alloccount += iinfo->stackvarscount;
438 if (iinfo->synclocal != UNUSED)
442 if (iinfo->javalocals_start)
443 MCOPY(javalocals, iinfo->javalocals_start, s4, m->maxlocals);
446 case ICMD_INLINE_END:
447 iinfo = iptr->sx.s23.s3.inlineinfo;
449 if (iinfo->javalocals_end)
450 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
451 iinfo = iinfo->parent;
454 } /* end instruction loop */
456 /* create replacement points at targets of backward branches */
457 /* We only need the replacement point there, if there is no */
458 /* replacement point inside the block. */
460 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
461 if (count > startcount) {
462 /* we don't need it */
463 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
467 alloccount += bptr->indepth;
468 if (bptr->inlineinfo)
469 alloccount -= bptr->inlineinfo->throughcount;
471 for (i=0; i<bptr->method->maxlocals; ++i)
472 if (bptr->javalocals[i] != UNUSED)
477 } /* end basicblock loop */
479 /* if no points were found, there's nothing to do */
484 /* allocate replacement point array and allocation array */
486 rplpoints = MNEW(rplpoint, count);
487 regalloc = MNEW(rplalloc, alloccount);
490 /* initialize replacement point structs */
494 /* XXX try to share code with the counting loop! */
496 for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
499 if (bptr->flags < BBFINISHED)
502 /* get info about this block */
505 iinfo = bptr->inlineinfo;
507 /* initialize javalocals at the start of this block */
509 if (bptr->javalocals)
510 MCOPY(javalocals, bptr->javalocals, s4, m->maxlocals);
512 for (i=0; i<m->maxlocals; ++i)
513 javalocals[i] = UNUSED;
515 /* create replacement points at targets of backward branches */
517 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
519 i = (iinfo) ? iinfo->throughcount : 0;
520 replace_create_replacement_point(jd, iinfo, rp++,
521 bptr->type, bptr->iinstr, &ra,
522 bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
525 /* iterate over the instructions */
528 iend = iptr + bptr->icount;
530 for (; iptr != iend; ++iptr) {
532 case ICMD_INVOKESTATIC:
533 case ICMD_INVOKESPECIAL:
534 case ICMD_INVOKEVIRTUAL:
535 case ICMD_INVOKEINTERFACE:
536 INSTRUCTION_GET_METHODDESC(iptr, md);
538 i = (iinfo) ? iinfo->throughcount : 0;
539 replace_create_replacement_point(jd, iinfo, rp++,
540 RPLPOINT_TYPE_CALL, iptr, &ra,
541 javalocals, iptr->sx.s23.s2.args,
542 iptr->s1.argcount - i,
551 /* XXX share code with stack.c */
552 j = iptr->dst.varindex;
553 i = iptr->sx.s23.s3.javaindex;
555 if (iptr->flags.bits & INS_FLAG_RETADDR)
556 javalocals[i] = iptr->sx.s23.s2.retaddrnr;
559 if (iptr->flags.bits & INS_FLAG_KILL_PREV)
560 javalocals[i-1] = UNUSED;
561 if (iptr->flags.bits & INS_FLAG_KILL_NEXT)
562 javalocals[i+1] = UNUSED;
571 replace_create_replacement_point(jd, iinfo, rp++,
572 RPLPOINT_TYPE_RETURN, iptr, &ra,
573 NULL, &(iptr->s1.varindex), 1, 0);
577 replace_create_replacement_point(jd, iinfo, rp++,
578 RPLPOINT_TYPE_RETURN, iptr, &ra,
582 case ICMD_INLINE_START:
583 calleeinfo = iptr->sx.s23.s3.inlineinfo;
586 replace_create_replacement_point(jd, iinfo, rp++,
587 RPLPOINT_TYPE_INLINE, iptr, &ra,
589 calleeinfo->stackvars, calleeinfo->stackvarscount,
590 calleeinfo->paramcount);
592 if (calleeinfo->synclocal != UNUSED) {
593 ra->index = RPLALLOC_SYNC;
594 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
595 ra->flags = jd->var[calleeinfo->synclocal].flags & INMEMORY;
598 rp[-1].regalloccount++;
603 if (iinfo->javalocals_start)
604 MCOPY(javalocals, iinfo->javalocals_start, s4, m->maxlocals);
607 case ICMD_INLINE_END:
608 iinfo = iptr->sx.s23.s3.inlineinfo;
610 if (iinfo->javalocals_end)
611 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
612 iinfo = iinfo->parent;
615 } /* end instruction loop */
616 } /* end basicblock loop */
618 assert((rp - rplpoints) == count);
619 assert((ra - regalloc) == alloccount);
621 /* store the data in the codeinfo */
623 code->rplpoints = rplpoints;
624 code->rplpointcount = count;
625 code->regalloc = regalloc;
626 code->regalloccount = alloccount;
627 code->globalcount = 0;
628 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
629 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
630 code->memuse = rd->memuse;
631 code->stackframesize = jd->cd->stackframesize;
633 REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
634 REPLACE_COUNT_INC(stat_regallocs, alloccount);
636 /* everything alright */
642 /* replace_free_replacement_points *********************************************
644 Free memory used by replacement points.
647 code.............codeinfo whose replacement points should be freed.
649 *******************************************************************************/
651 void replace_free_replacement_points(codeinfo *code)
656 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
659 MFREE(code->regalloc,rplalloc,code->regalloccount);
661 code->rplpoints = NULL;
662 code->rplpointcount = 0;
663 code->regalloc = NULL;
664 code->regalloccount = 0;
665 code->globalcount = 0;
669 /* replace_activate_replacement_point ******************************************
671 Activate a replacement point. When this function returns, the
672 replacement point is "armed", that is each thread reaching this point
673 will be replace to `target`.
676 rp...............replacement point to activate
677 target...........target of replacement
679 *******************************************************************************/
681 void replace_activate_replacement_point(rplpoint *rp,rplpoint *target)
683 assert(rp->target == NULL);
685 DOLOG( printf("activate replacement point:\n");
686 replace_replacement_point_println(rp, 1); fflush(stdout); );
690 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
691 md_patch_replacement_point(rp);
696 /* replace_deactivate_replacement_point ****************************************
698 Deactivate a replacement point. When this function returns, the
699 replacement point is "un-armed", that is a each thread reaching this point
700 will just continue normally.
703 rp...............replacement point to deactivate
705 *******************************************************************************/
707 void replace_deactivate_replacement_point(rplpoint *rp)
711 DOLOG( printf("deactivate replacement point:\n");
712 replace_replacement_point_println(rp, 1); fflush(stdout); );
716 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
717 md_patch_replacement_point(rp);
722 /* replace_read_value **********************************************************
724 Read a value with the given allocation from the execution state.
727 es...............execution state
728 sp...............stack pointer of the execution state (XXX eliminate?)
729 ra...............allocation
730 javaval..........where to put the value
733 *javaval.........the value
735 *******************************************************************************/
737 static void replace_read_value(executionstate_t *es,
742 if (ra->flags & INMEMORY) {
743 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
744 #ifdef HAS_4BYTE_STACKSLOT
745 if (IS_2_WORD_TYPE(ra->type)) {
746 *javaval = *(u8*)(sp + ra->regoff);
750 *javaval = sp[ra->regoff];
751 #ifdef HAS_4BYTE_STACKSLOT
756 /* allocated register */
757 if (IS_FLT_DBL_TYPE(ra->type)) {
758 *javaval = es->fltregs[ra->regoff];
761 *javaval = es->intregs[ra->regoff];
767 /* replace_write_value *********************************************************
769 Write a value to the given allocation in the execution state.
772 es...............execution state
773 sp...............stack pointer of the execution state (XXX eliminate?)
774 ra...............allocation
775 *javaval.........the value
777 *******************************************************************************/
779 static void replace_write_value(executionstate_t *es,
784 if (ra->flags & INMEMORY) {
785 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
786 #ifdef HAS_4BYTE_STACKSLOT
787 if (IS_2_WORD_TYPE(ra->type)) {
788 *(u8*)(sp + ra->regoff) = *javaval;
792 sp[ra->regoff] = *javaval;
793 #ifdef HAS_4BYTE_STACKSLOT
798 /* allocated register */
799 if (IS_FLT_DBL_TYPE(ra->type)) {
800 es->fltregs[ra->regoff] = *javaval;
803 es->intregs[ra->regoff] = *javaval;
809 /* replace_read_executionstate *************************************************
811 Read the given executions state and translate it to a source frame.
814 rp...............replacement point at which `es` was taken
815 es...............execution state
816 ss...............where to put the source state
819 *ss..............the source state derived from the execution state
821 *******************************************************************************/
823 static void replace_read_executionstate(rplpoint *rp,
824 executionstate_t *es,
833 sourceframe_t *frame;
840 topslot = TOP_IS_NORMAL;
844 sp = (stackslot_t *) es->sp;
846 /* in some cases the top stack slot is passed in REG_ITMP1 */
848 if (rp->type == BBTYPE_EXH) {
849 topslot = TOP_IS_IN_ITMP1;
852 /* calculate base stack pointer */
854 basesp = sp + code_get_stack_frame_size(code);
856 /* create the source frame */
858 frame = DNEW(sourceframe_t);
859 frame->up = ss->frames;
860 frame->method = rp->method;
862 frame->syncslotcount = 0;
863 frame->syncslots = NULL;
865 frame->debug_rp = rp;
870 /* read local variables */
872 count = m->maxlocals;
873 frame->javalocalcount = count;
874 frame->javalocals = DMNEW(u8, count);
875 frame->javalocaltype = DMNEW(u1, count);
878 /* mark values as undefined */
879 for (i=0; i<count; ++i) {
880 frame->javalocals[i] = (u8) 0x00dead0000dead00ULL;
881 frame->javalocaltype[i] = TYPE_VOID;
884 /* some entries in the intregs array are not meaningful */
885 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
886 es->intregs[REG_SP ] = (u8) 0x11dead1111dead11ULL;
888 es->intregs[REG_PV ] = (u8) 0x11dead1111dead11ULL;
890 #endif /* !defined(NDEBUG) */
892 /* read javalocals */
894 count = rp->regalloccount;
897 while (count && (i = ra->index) >= 0) {
898 assert(i < m->maxlocals);
899 frame->javalocaltype[i] = ra->type;
900 if (ra->type == TYPE_RET)
901 frame->javalocals[i] = ra->regoff;
903 replace_read_value(es, sp, ra, frame->javalocals + i);
908 /* read stack slots */
910 frame->javastackdepth = count;
911 frame->javastack = DMNEW(u8, count);
912 frame->javastacktype = DMNEW(u1, count);
915 /* mark values as undefined */
916 for (i=0; i<count; ++i) {
917 frame->javastack[i] = (u8) 0x00dead0000dead00ULL;
918 frame->javastacktype[i] = TYPE_VOID;
920 #endif /* !defined(NDEBUG) */
924 /* the first stack slot is special in SBR and EXH blocks */
926 if (topslot == TOP_IS_ON_STACK) {
929 assert(ra->index == RPLALLOC_STACK);
930 frame->javastack[i] = sp[-1];
931 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
936 else if (topslot == TOP_IS_IN_ITMP1) {
939 assert(ra->index == RPLALLOC_STACK);
940 frame->javastack[i] = es->intregs[REG_ITMP1];
941 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
946 else if (topslot == TOP_IS_VOID) {
949 assert(ra->index == RPLALLOC_STACK);
950 frame->javastack[i] = 0;
951 frame->javastacktype[i] = TYPE_VOID;
957 /* read remaining stack slots */
959 for (; count--; ra++) {
960 if (ra->index == RPLALLOC_SYNC) {
961 assert(rp->type == RPLPOINT_TYPE_INLINE);
963 /* only read synchronization slots when traversing an inline point */
966 sourceframe_t *calleeframe = frame->up;
968 assert(calleeframe->syncslotcount == 0);
969 assert(calleeframe->syncslots == NULL);
971 calleeframe->syncslotcount = 1;
972 calleeframe->syncslots = DMNEW(u8, 1);
973 replace_read_value(es,sp,ra,calleeframe->syncslots);
976 frame->javastackdepth--;
980 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
982 /* do not read parameters of calls down the call chain */
984 if (!topframe && ra->index == RPLALLOC_PARAM) {
985 frame->javastackdepth--;
988 if (ra->type == TYPE_RET)
989 frame->javastack[i] = ra->regoff;
991 replace_read_value(es,sp,ra,frame->javastack + i);
992 frame->javastacktype[i] = ra->type;
999 /* replace_write_executionstate ************************************************
1001 Translate the given source state into an execution state.
1004 rp...............replacement point for which execution state should be
1006 es...............where to put the execution state
1007 ss...............the given source state
1010 *es..............the execution state derived from the source state
1012 *******************************************************************************/
1014 static void replace_write_executionstate(rplpoint *rp,
1015 executionstate_t *es,
1024 sourceframe_t *frame;
1027 stackslot_t *basesp;
1031 topslot = TOP_IS_NORMAL;
1033 /* pop a source frame */
1037 ss->frames = frame->up;
1039 /* calculate stack pointer */
1041 sp = (stackslot_t *) es->sp;
1043 basesp = sp + code_get_stack_frame_size(code);
1045 /* in some cases the top stack slot is passed in REG_ITMP1 */
1047 if (rp->type == BBTYPE_EXH) {
1048 topslot = TOP_IS_IN_ITMP1;
1051 /* write javalocals */
1054 count = rp->regalloccount;
1056 while (count && (i = ra->index) >= 0) {
1057 assert(i < m->maxlocals);
1058 assert(i < frame->javalocalcount);
1059 assert(ra->type == frame->javalocaltype[i]);
1060 if (ra->type == TYPE_RET) {
1061 /* XXX assert that it matches this rplpoint */
1064 replace_write_value(es, sp, ra, frame->javalocals + i);
1069 /* write stack slots */
1073 /* the first stack slot is special in SBR and EXH blocks */
1075 if (topslot == TOP_IS_ON_STACK) {
1078 assert(ra->index == RPLALLOC_STACK);
1079 assert(i < frame->javastackdepth);
1080 assert(frame->javastacktype[i] == TYPE_ADR);
1081 sp[-1] = frame->javastack[i];
1086 else if (topslot == TOP_IS_IN_ITMP1) {
1089 assert(ra->index == RPLALLOC_STACK);
1090 assert(i < frame->javastackdepth);
1091 assert(frame->javastacktype[i] == TYPE_ADR);
1092 es->intregs[REG_ITMP1] = frame->javastack[i];
1097 else if (topslot == TOP_IS_VOID) {
1100 assert(ra->index == RPLALLOC_STACK);
1101 assert(i < frame->javastackdepth);
1102 assert(frame->javastacktype[i] == TYPE_VOID);
1108 /* write remaining stack slots */
1110 for (; count--; ra++) {
1111 if (ra->index == RPLALLOC_SYNC) {
1112 assert(rp->type == RPLPOINT_TYPE_INLINE);
1114 /* only write synchronization slots when traversing an inline point */
1118 assert(frame->up->syncslotcount == 1); /* XXX need to understand more cases */
1119 assert(frame->up->syncslots != NULL);
1121 replace_write_value(es,sp,ra,frame->up->syncslots);
1126 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1128 /* do not write parameters of calls down the call chain */
1130 if (!topframe && ra->index == RPLALLOC_PARAM) {
1134 assert(i < frame->javastackdepth);
1135 assert(ra->type == frame->javastacktype[i]);
1136 if (ra->type == TYPE_RET) {
1137 /* XXX assert that it matches this rplpoint */
1140 replace_write_value(es,sp,ra,frame->javastack + i);
1152 /* replace_pop_activation_record ***********************************************
1154 Peel a stack frame from the execution state.
1156 *** This function imitates the effects of the method epilog ***
1157 *** and returning from the method call. ***
1160 es...............execution state
1161 frame............source frame, receives synchronization slots
1164 *es..............the execution state after popping the stack frame
1166 *******************************************************************************/
1168 bool replace_pop_activation_record(executionstate_t *es,
1169 sourceframe_t *frame)
1177 stackslot_t *basesp;
1183 /* read the return address */
1185 ra = md_stacktrace_get_returnaddress(es->sp,
1186 SIZE_OF_STACKSLOT * es->code->stackframesize);
1188 DOLOG( printf("return address: %p\n", (void*)ra); );
1190 /* find the new codeinfo */
1192 pv = md_codegen_get_pv_from_pc(ra);
1194 DOLOG( printf("PV = %p\n", (void*) pv); );
1199 code = *(codeinfo **)(pv + CodeinfoPointer);
1201 DOLOG( printf("CODE = %p\n", (void*) code); );
1206 /* calculate the base of the stack frame */
1208 sp = (stackslot_t *) es->sp;
1209 basesp = sp + es->code->stackframesize;
1211 /* read slots used for synchronization */
1213 assert(frame->syncslotcount == 0);
1214 assert(frame->syncslots == NULL);
1215 count = code_get_sync_slot_count(es->code);
1216 frame->syncslotcount = count;
1217 frame->syncslots = DMNEW(u8, count);
1218 for (i=0; i<count; ++i) {
1219 frame->syncslots[i] = sp[es->code->memuse + i];
1222 /* restore saved int registers */
1225 for (i=0; i<es->code->savedintcount; ++i) {
1226 while (nregdescint[--reg] != REG_SAV)
1228 es->intregs[reg] = *--basesp;
1231 /* restore saved flt registers */
1235 for (i=0; i<es->code->savedfltcount; ++i) {
1236 while (nregdescfloat[--reg] != REG_SAV)
1238 basesp -= STACK_SLOTS_PER_FLOAT;
1239 es->fltregs[reg] = *(u8*)basesp;
1242 /* Set the new pc. Subtract one so we do not hit the replacement point */
1243 /* of the instruction following the call, if there is one. */
1247 /* adjust the stackpointer */
1249 es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1250 es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1255 #if !defined(NDEBUG)
1257 for (i=0; i<INT_REG_CNT; ++i)
1258 if (nregdescint[i] != REG_SAV)
1259 es->intregs[i] = 0x33dead3333dead33ULL;
1260 for (i=0; i<FLT_REG_CNT; ++i)
1261 if (nregdescfloat[i] != REG_SAV)
1262 es->fltregs[i] = 0x33dead3333dead33ULL;
1263 #endif /* !defined(NDEBUG) */
1269 /* replace_push_activation_record **********************************************
1271 Push a stack frame onto the execution state.
1273 *** This function imitates the effects of a call and the ***
1274 *** method prolog of the callee. ***
1277 es...............execution state
1278 rpcall...........the replacement point at the call site
1279 calleecode.......the codeinfo of the callee
1280 frame............source frame, only the synch. slots are used
1283 *es..............the execution state after pushing the stack frame
1285 *******************************************************************************/
1287 void replace_push_activation_record(executionstate_t *es,
1289 codeinfo *calleecode,
1290 sourceframe_t *frame)
1295 stackslot_t *basesp;
1299 assert(rpcall && rpcall->type == RPLPOINT_TYPE_CALL);
1303 /* write the return address */
1305 es->sp -= SIZE_OF_STACKSLOT;
1307 DOLOG( printf("writing return address %p to %p\n",
1308 (void*) (rpcall->pc + rpcall->callsize),
1311 *((stackslot_t *)es->sp) = (stackslot_t) (rpcall->pc + rpcall->callsize);
1313 /* we move into a new code unit */
1315 es->code = calleecode;
1317 /* set the new pc XXX not needed */
1319 es->pc = es->code->entrypoint;
1321 /* build the stackframe */
1323 DOLOG( printf("building stackframe of %d words at %p\n",
1324 es->code->stackframesize, (void*)es->sp); );
1326 sp = (stackslot_t *) es->sp;
1329 sp -= es->code->stackframesize;
1332 /* in debug mode, invalidate stack frame first */
1334 #if !defined(NDEBUG)
1335 for (i=0; i<(basesp - sp); ++i) {
1336 sp[i] = 0xdeaddeadU;
1340 /* save int registers */
1343 for (i=0; i<es->code->savedintcount; ++i) {
1344 while (nregdescint[--reg] != REG_SAV)
1346 *--basesp = es->intregs[reg];
1348 #if !defined(NDEBUG)
1349 es->intregs[reg] = 0x44dead4444dead44ULL;
1353 /* save flt registers */
1357 for (i=0; i<es->code->savedfltcount; ++i) {
1358 while (nregdescfloat[--reg] != REG_SAV)
1360 basesp -= STACK_SLOTS_PER_FLOAT;
1361 *(u8*)basesp = es->fltregs[reg];
1363 #if !defined(NDEBUG)
1364 es->fltregs[reg] = 0x44dead4444dead44ULL;
1368 /* write slots used for synchronization */
1370 count = code_get_sync_slot_count(es->code);
1371 assert(count == frame->syncslotcount);
1372 for (i=0; i<count; ++i) {
1373 sp[es->code->memuse + i] = frame->syncslots[i];
1378 es->pv = es->code->entrypoint;
1382 /* replace_find_replacement_point **********************************************
1384 Find the replacement point in the given code corresponding to the
1385 position given in the source frame.
1388 code.............the codeinfo in which to search the rplpoint
1389 ss...............the source state defining the position to look for
1390 parent...........parent replacement point to match
1393 the replacement point
1395 *******************************************************************************/
1397 rplpoint * replace_find_replacement_point(codeinfo *code,
1401 sourceframe_t *frame;
1414 DOLOG( printf("searching replacement point for:\n");
1415 replace_source_frame_println(frame); );
1419 DOLOG( printf("code = %p\n", (void*)code); );
1421 rp = code->rplpoints;
1422 i = code->rplpointcount;
1424 if (rp->id == frame->id && rp->method == frame->method
1425 && rp->parent == parent)
1427 /* check if returnAddresses match */
1428 /* XXX optimize: only do this if JSRs in method */
1429 DOLOG( printf("checking match for:");
1430 replace_replacement_point_println(rp, 1); fflush(stdout); );
1433 for (j = rp->regalloccount; j--; ++ra) {
1434 if (ra->type == TYPE_RET) {
1435 if (ra->index == RPLALLOC_STACK) {
1436 assert(stacki < frame->javastackdepth);
1437 if (frame->javastack[stacki] != ra->regoff)
1442 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
1443 if (frame->javalocals[ra->index] != ra->regoff)
1457 return NULL; /* NOT REACHED */
1461 /* replace_me ******************************************************************
1463 This function is called by asm_replacement_out when a thread reaches
1464 a replacement point. `replace_me` must map the execution state to the
1465 target replacement point and let execution continue there.
1467 This function never returns!
1470 rp...............replacement point that has been reached
1471 es...............execution state read by asm_replacement_out
1473 *******************************************************************************/
1475 void replace_me(rplpoint *rp, executionstate_t *es)
1480 rplpoint *candidate;
1489 es->code = rp->code;
1491 DOLOG( printf("REPLACING: "); method_println(es->code->m); );
1492 REPLACE_COUNT(stat_replacements);
1494 /* mark start of dump memory area */
1496 dumpsize = dump_size();
1498 /* fetch the target of the replacement */
1500 target = rp->target;
1502 DOLOG( printf("replace_me(%p,%p)\n",(void*)rp,(void*)es); fflush(stdout);
1503 replace_replacement_point_println(rp, 1);
1504 replace_executionstate_println(es); );
1506 /* read execution state of old code */
1515 DOLOG( printf("recovering source state for%s:\n",
1516 (ss.frames == NULL) ? " TOPFRAME" : "");
1517 replace_replacement_point_println(candidate, 1); );
1519 replace_read_executionstate(candidate, es, &ss, ss.frames == NULL);
1520 REPLACE_COUNT(stat_frames);
1523 #if defined(REPLACE_STATISTICS)
1524 int adr = 0; int ret = 0; int prim = 0; int vd = 0; int n = 0;
1525 for (i=0; i<ss.frames->javalocalcount; ++i) {
1526 switch (ss.frames->javalocaltype[i]) {
1527 case TYPE_ADR: adr++; break;
1528 case TYPE_RET: ret++; break;
1529 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
1530 case TYPE_VOID: vd++; break;
1535 REPLACE_COUNT_DIST(stat_dist_locals, n);
1536 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
1537 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
1538 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
1539 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
1540 adr = ret = prim = n = 0;
1541 for (i=0; i<ss.frames->javastackdepth; ++i) {
1542 switch (ss.frames->javastacktype[i]) {
1543 case TYPE_ADR: adr++; break;
1544 case TYPE_RET: ret++; break;
1545 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
1549 REPLACE_COUNT_DIST(stat_dist_stack, n);
1550 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
1551 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
1552 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
1553 #endif /* defined(REPLACE_STATISTICS) */
1555 if (candidate->parent) {
1556 DOLOG( printf("INLINED!\n"); );
1557 candidate = candidate->parent;
1558 assert(candidate->type == RPLPOINT_TYPE_INLINE);
1559 REPLACE_COUNT(stat_unroll_inline);
1562 DOLOG( printf("UNWIND\n"); );
1563 REPLACE_COUNT(stat_unroll_call);
1564 if (!replace_pop_activation_record(es, ss.frames)) {
1565 DOLOG( printf("BREAKING\n"); );
1568 DOLOG( replace_executionstate_println(es); );
1570 rp = es->code->rplpoints;
1571 for (i=0; i<es->code->rplpointcount; ++i, ++rp)
1572 if (rp->pc <= es->pc)
1575 DOLOG( printf("NO CANDIDATE!\n"); );
1577 DOLOG( printf("found replacement point.\n");
1578 replace_replacement_point_println(candidate, 1); );
1579 assert(candidate->type == RPLPOINT_TYPE_CALL);
1582 } while (candidate);
1584 REPLACE_COUNT_DIST(stat_dist_frames, depth);
1585 DOLOG( replace_sourcestate_println(&ss); );
1587 /* write execution state of new code */
1589 DOLOG( replace_executionstate_println(es); );
1593 /* XXX get new code */
1598 candidate = replace_find_replacement_point(code, &ss, parent);
1600 DOLOG( printf("creating execution state for%s:\n",
1601 (ss.frames->up == NULL) ? " TOPFRAME" : "");
1602 replace_replacement_point_println(ss.frames->debug_rp, 1);
1603 replace_replacement_point_println(candidate, 1); );
1605 replace_write_executionstate(candidate, es, &ss, ss.frames->up == NULL);
1606 if (ss.frames == NULL)
1608 DOLOG( replace_executionstate_println(es); );
1610 if (candidate->type == RPLPOINT_TYPE_CALL) {
1611 if (!ss.frames->method->code || ss.frames->method->code->invalid) {
1612 REPLACE_COUNT(stat_recompile);
1613 if (!jit_recompile(ss.frames->method))
1614 /* XXX exception */;
1616 code = ss.frames->method->code;
1618 DOLOG( printf("pushing activation record for:\n");
1619 replace_replacement_point_println(candidate, 1); );
1620 replace_push_activation_record(es, candidate, code, ss.frames);
1626 DOLOG( replace_executionstate_println(es); );
1629 DOLOG( replace_executionstate_println(es); );
1632 if (candidate == origrp) {
1633 printf("WARNING: identity replacement, turning off rp to avoid infinite loop");
1634 replace_deactivate_replacement_point(origrp);
1637 /* release dump area */
1639 dump_release(dumpsize);
1641 /* enter new code */
1643 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
1645 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
1646 asm_replacement_in(es);
1648 abort(); /* NOT REACHED */
1652 /* replace_replacement_point_println *******************************************
1654 Print replacement point info.
1657 rp...............the replacement point to print
1659 *******************************************************************************/
1661 #if !defined(NDEBUG)
1663 #define TYPECHAR(t) (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
1665 static char *replace_type_str[] = {
1675 void replace_replacement_point_println(rplpoint *rp, int depth)
1681 printf("(rplpoint *)NULL\n");
1685 for (j=0; j<depth; ++j)
1688 printf("rplpoint (id %d) %p pc:%p+%d out:%p target:%p mcode:%016llx type:%s",
1689 rp->id, (void*)rp,rp->pc,rp->callsize,rp->outcode,(void*)rp->target,
1690 (unsigned long long)rp->mcode,replace_type_str[rp->type]);
1691 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
1693 printf(" parent:%p\n", (void*)rp->parent);
1694 for (j=0; j<depth; ++j)
1696 printf("ra:%d = [", rp->regalloccount);
1698 for (j=0; j<rp->regalloccount; ++j) {
1701 index = rp->regalloc[j].index;
1703 case RPLALLOC_STACK: printf("S"); break;
1704 case RPLALLOC_PARAM: printf("P"); break;
1705 case RPLALLOC_SYNC : printf("Y"); break;
1706 default: printf("%d", index);
1708 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
1709 if (rp->regalloc[j].type == TYPE_RET) {
1710 printf("ret(L%03d)", rp->regalloc[j].regoff);
1713 show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
1718 for (j=0; j<depth; ++j)
1721 method_print(rp->method);
1728 /* replace_show_replacement_points *********************************************
1730 Print replacement point info.
1733 code.............codeinfo whose replacement points should be printed.
1735 *******************************************************************************/
1737 #if !defined(NDEBUG)
1738 void replace_show_replacement_points(codeinfo *code)
1746 printf("(codeinfo *)NULL\n");
1750 printf("\treplacement points: %d\n",code->rplpointcount);
1752 printf("\ttotal allocations : %d\n",code->regalloccount);
1753 printf("\tsaved int regs : %d\n",code->savedintcount);
1754 printf("\tsaved flt regs : %d\n",code->savedfltcount);
1755 printf("\tmemuse : %d\n",code->memuse);
1759 for (i=0; i<code->rplpointcount; ++i) {
1760 rp = code->rplpoints + i;
1762 assert(rp->code == code);
1765 parent = rp->parent;
1768 parent = parent->parent;
1770 replace_replacement_point_println(rp, depth);
1776 /* replace_executionstate_println **********************************************
1778 Print execution state
1781 es...............the execution state to print
1783 *******************************************************************************/
1785 #if !defined(NDEBUG)
1786 void replace_executionstate_println(executionstate_t *es)
1794 printf("(executionstate_t *)NULL\n");
1798 printf("executionstate_t:\n");
1799 printf("\tpc = %p",(void*)es->pc);
1800 printf(" sp = %p",(void*)es->sp);
1801 printf(" pv = %p\n",(void*)es->pv);
1802 #if defined(ENABLE_DISASSEMBLER)
1803 for (i=0; i<INT_REG_CNT; ++i) {
1808 printf("%-3s = %016llx",regs[i],(unsigned long long)es->intregs[i]);
1812 for (i=0; i<FLT_REG_CNT; ++i) {
1817 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
1823 sp = (stackslot_t *) es->sp;
1828 methoddesc *md = es->code->m->parseddesc;
1829 slots = code_get_stack_frame_size(es->code);
1830 extraslots = 1 + md->memuse;
1837 printf("\tstack slots(+%d) at sp:", extraslots);
1838 for (i=0; i<slots+extraslots; ++i) {
1841 printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
1842 #ifdef HAS_4BYTE_STACKSLOT
1843 printf("%08lx",(unsigned long)*sp++);
1845 printf("%016llx",(unsigned long long)*sp++);
1847 printf("%c", (i >= slots) ? ')' : ' ');
1852 printf("\tcode: %p", (void*)es->code);
1853 if (es->code != NULL) {
1854 printf(" stackframesize=%d ", es->code->stackframesize);
1855 method_print(es->code->m);
1863 #if !defined(NDEBUG)
1864 void java_value_print(s4 type, u8 value)
1866 java_objectheader *obj;
1869 printf("%016llx",(unsigned long long) value);
1871 if (type < 0 || type > TYPE_RET)
1872 printf(" <INVALID TYPE:%d>", type);
1874 printf(" %s", show_jit_type_names[type]);
1876 if (type == TYPE_ADR && value != 0) {
1877 obj = (java_objectheader *) (ptrint) value;
1879 utf_display_printable_ascii_classname(obj->vftbl->class->name);
1881 if (obj->vftbl->class == class_java_lang_String) {
1883 u = javastring_toutf((java_lang_String *)obj, false);
1884 utf_display_printable_ascii(u);
1888 else if (type == TYPE_INT || type == TYPE_LNG) {
1889 printf(" %lld", (long long) value);
1892 #endif /* !defined(NDEBUG) */
1895 #if !defined(NDEBUG)
1896 void replace_source_frame_println(sourceframe_t *frame)
1902 method_println(frame->method);
1903 printf("\tid: %d\n", frame->id);
1906 if (frame->javalocalcount) {
1907 printf("\tlocals (%d):\n",frame->javalocalcount);
1908 for (i=0; i<frame->javalocalcount; ++i) {
1909 t = frame->javalocaltype[i];
1910 if (t == TYPE_VOID) {
1911 printf("\tlocal[ %2d] = void\n",i);
1914 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
1915 java_value_print(t, frame->javalocals[i]);
1922 if (frame->javastackdepth) {
1923 printf("\tstack (depth %d):\n",frame->javastackdepth);
1924 for (i=0; i<frame->javastackdepth; ++i) {
1925 t = frame->javastacktype[i];
1926 if (t == TYPE_VOID) {
1927 printf("\tstack[%2d] = void", i);
1930 printf("\tstack[%2d] = ",i);
1931 java_value_print(frame->javastacktype[i], frame->javastack[i]);
1938 if (frame->syncslotcount) {
1939 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
1940 for (i=0; i<frame->syncslotcount; ++i) {
1941 printf("\tslot[%2d] = ",i);
1942 #ifdef HAS_4BYTE_STACKSLOT
1943 printf("%08lx\n",(unsigned long) frame->syncslots[i]);
1945 printf("%016llx\n",(unsigned long long) frame->syncslots[i]);
1951 #endif /* !defined(NDEBUG) */
1954 /* replace_sourcestate_println *************************************************
1959 ss...............the source state to print
1961 *******************************************************************************/
1963 #if !defined(NDEBUG)
1964 void replace_sourcestate_println(sourcestate_t *ss)
1967 sourceframe_t *frame;
1970 printf("(sourcestate_t *)NULL\n");
1974 printf("sourcestate_t:\n");
1976 for (i=0, frame = ss->frames; frame != NULL; frame = frame->up, ++i) {
1977 printf(" frame %d:\n", i);
1978 replace_source_frame_println(frame);
1984 * These are local overrides for various environment variables in Emacs.
1985 * Please do not remove this and leave it at the end of the file, where
1986 * Emacs will automagically detect them.
1987 * ---------------------------------------------------------------------
1990 * indent-tabs-mode: t
1994 * vim:noexpandtab:sw=4:ts=4: