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/jit/abi.h"
47 #include "vm/jit/jit.h"
48 #include "vm/jit/replace.h"
49 #include "vm/jit/asmpart.h"
50 #include "vm/jit/disass.h"
53 /*** constants used internally ************************************************/
55 #define TOP_IS_NORMAL 0
56 #define TOP_IS_ON_STACK 1
57 #define TOP_IS_IN_ITMP1 2
59 /* replace_create_replacement_points *******************************************
61 Create the replacement points for the given code.
64 code.............codeinfo where replacement points should be stored
65 code->rplpoints must be NULL.
66 code->rplpointcount must be 0.
67 rd...............registerdata containing allocation info.
70 code->rplpoints.......set to the list of replacement points
71 code->rplpointcount...number of replacement points
72 code->regalloc........list of allocation info
73 code->regalloccount...total length of allocation info list
74 code->globalcount.....number of global allocations at the
75 start of code->regalloc
78 true.............everything ok
79 false............an exception has been thrown
81 *******************************************************************************/
83 bool replace_create_replacement_points(jitdata *jd)
102 /* get required compiler data */
107 /* assert that we wont overwrite already allocated data */
111 assert(code->rplpoints == NULL);
112 assert(code->rplpointcount == 0);
113 assert(code->regalloc == NULL);
114 assert(code->regalloccount == 0);
115 assert(code->globalcount == 0);
117 /* iterate over the basic block list to find replacement points */
124 for (bptr = jd->new_basicblocks; bptr; bptr = bptr->next) {
125 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
128 /* there will be a replacement point at the start of this block */
131 alloccount += bptr->indepth;
134 /* if no points were found, there's nothing to do */
139 /* count global register allocations */
143 for (i=0; i<m->maxlocals; ++i) {
145 for (t=0; t<5; ++t) {
146 #if defined(ENABLE_INTRP)
149 if (rd->locals[i][t].type == t) {
153 #if defined(ENABLE_INTRP)
158 globalcount++; /* dummy rplalloc */
161 alloccount += globalcount;
163 /* allocate replacement point array and allocation array */
165 rplpoints = MNEW(rplpoint,count);
166 regalloc = MNEW(rplalloc,alloccount);
169 /* store global register allocations */
171 for (i=0; i<m->maxlocals; ++i) {
173 for (t=0; t<5; ++t) {
174 #if defined(ENABLE_INTRP)
177 if (rd->locals[i][t].type == t) {
178 ra->flags = rd->locals[i][t].flags & (INMEMORY);
179 ra->index = rd->locals[i][t].regoff;
181 ra->next = (indexused) ? 0 : 1;
185 #if defined(ENABLE_INTRP)
199 /* initialize replacement point structs */
203 for (bptr = jd->new_basicblocks; bptr; bptr = bptr->next) {
204 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
207 /* there will be a replacement point at the start of this block */
209 rp->pc = NULL; /* set by codegen */
210 rp->outcode = NULL; /* set by codegen */
215 rp->type = bptr->type;
217 /* store local allocation info */
219 for (sp = bptr->instack; sp; sp = sp->prev) {
220 ra->flags = sp->flags & (INMEMORY);
221 ra->index = sp->regoff;
227 rp->regalloccount = ra - rp->regalloc;
232 /* store the data in the codeinfo */
234 code->rplpoints = rplpoints;
235 code->rplpointcount = count;
236 code->regalloc = regalloc;
237 code->regalloccount = alloccount;
238 code->globalcount = globalcount;
239 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
240 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
241 code->memuse = rd->memuse;
243 /* everything alright */
249 /* replace_free_replacement_points *********************************************
251 Free memory used by replacement points.
254 code.............codeinfo whose replacement points should be freed.
256 *******************************************************************************/
258 void replace_free_replacement_points(codeinfo *code)
263 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
266 MFREE(code->regalloc,rplalloc,code->regalloccount);
268 code->rplpoints = NULL;
269 code->rplpointcount = 0;
270 code->regalloc = NULL;
271 code->regalloccount = 0;
272 code->globalcount = 0;
275 /* replace_activate_replacement_point ******************************************
277 Activate a replacement point. When this function returns, the
278 replacement point is "armed", that is each thread reaching this point
279 will be replace to `target`.
282 rp...............replacement point to activate
283 target...........target of replacement
285 *******************************************************************************/
287 void replace_activate_replacement_point(rplpoint *rp,rplpoint *target)
289 assert(rp->target == NULL);
292 printf("activate replacement point: ");
293 replace_replacement_point_println(rp);
299 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
300 md_patch_replacement_point(rp);
304 /* replace_deactivate_replacement_point ****************************************
306 Deactivate a replacement point. When this function returns, the
307 replacement point is "un-armed", that is a each thread reaching this point
308 will just continue normally.
311 rp...............replacement point to deactivate
313 *******************************************************************************/
315 void replace_deactivate_replacement_point(rplpoint *rp)
320 printf("deactivate replacement point: ");
321 replace_replacement_point_println(rp);
327 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
328 md_patch_replacement_point(rp);
332 /* replace_read_executionstate *************************************************
334 Read the given executions state and translate it to a source state.
337 rp...............replacement point at which `es` was taken
338 es...............execution state
339 ss...............where to put the source state
342 *ss..............the source state derived from the execution state
344 *******************************************************************************/
346 inline static void replace_read_value(executionstate *es,
347 #ifdef HAS_4BYTE_STACKSLOT
355 if (ra->flags & INMEMORY) {
356 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
357 #ifdef HAS_4BYTE_STACKSLOT
358 if (IS_2_WORD_TYPE(ra->type)) {
359 *javaval = *(u8*)(sp + ra->index);
363 *javaval = sp[ra->index];
364 #ifdef HAS_4BYTE_STACKSLOT
369 /* allocated register */
370 if (IS_FLT_DBL_TYPE(ra->type)) {
371 *javaval = es->fltregs[ra->index];
374 *javaval = es->intregs[ra->index];
379 inline static void replace_write_value(executionstate *es,
380 #ifdef HAS_4BYTE_STACKSLOT
388 if (ra->flags & INMEMORY) {
389 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
390 #ifdef HAS_4BYTE_STACKSLOT
391 if (IS_2_WORD_TYPE(ra->type)) {
392 *(u8*)(sp + ra->index) = *javaval;
396 sp[ra->index] = *javaval;
397 #ifdef HAS_4BYTE_STACKSLOT
402 /* allocated register */
403 if (IS_FLT_DBL_TYPE(ra->type)) {
404 es->fltregs[ra->index] = *javaval;
407 es->intregs[ra->index] = *javaval;
412 static void replace_read_executionstate(rplpoint *rp,executionstate *es,
424 #ifdef HAS_4BYTE_STACKSLOT
435 topslot = TOP_IS_NORMAL;
439 #ifdef HAS_4BYTE_STACKSLOT
445 /* on some architectures the returnAddress is passed on the stack by JSR */
447 #if defined(__I386__) || defined(__X86_64__)
448 if (rp->type == BBTYPE_SBR) {
450 topslot = TOP_IS_ON_STACK;
454 /* in some cases the top stack slot is passed in REG_ITMP1 */
456 if ( (rp->type == BBTYPE_EXH)
457 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)
458 || (rp->type == BBTYPE_SBR)
462 topslot = TOP_IS_IN_ITMP1;
465 /* calculate base stack pointer */
467 basesp = sp + code_get_stack_frame_size(code);
469 ss->stackbase = (u1*) basesp;
471 /* read local variables */
473 count = m->maxlocals;
474 ss->javalocalcount = count;
475 ss->javalocals = DMNEW(u8,count * 5);
478 /* mark values as undefined */
479 for (i=0; i<count*5; ++i)
480 ss->javalocals[i] = (u8) 0x00dead0000dead00ULL;
482 /* some entries in the intregs array are not meaningful */
483 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
484 es->intregs[REG_SP ] = (u8) 0x11dead1111dead11ULL;
486 es->intregs[REG_PV ] = (u8) 0x11dead1111dead11ULL;
493 for (allocs = code->globalcount; allocs--; ra++) {
498 continue; /* dummy rplalloc */
500 replace_read_value(es,sp,ra,ss->javalocals + (5*i+t));
503 /* read stack slots */
505 count = rp->regalloccount;
506 ss->javastackdepth = count;
507 ss->javastack = DMNEW(u8,count);
510 /* mark values as undefined */
511 for (i=0; i<count; ++i)
512 ss->javastack[i] = (u8) 0x00dead0000dead00ULL;
518 /* the first stack slot is special in SBR and EXH blocks */
520 if (topslot == TOP_IS_ON_STACK) {
523 ss->javastack[i] = sp[-1];
528 else if (topslot == TOP_IS_IN_ITMP1) {
531 ss->javastack[i] = es->intregs[REG_ITMP1];
537 /* read remaining stack slots */
539 for (; count--; ra++, i++) {
542 replace_read_value(es,sp,ra,ss->javastack + i);
545 /* read unused callee saved int regs */
548 for (i=0; count > code->savedintcount; ++i) {
549 assert(i < INT_REG_CNT);
550 if (nregdescint[i] == REG_SAV)
551 ss->savedintregs[--count] = es->intregs[i];
554 /* read saved int regs */
556 for (i=0; i<code->savedintcount; ++i) {
557 ss->savedintregs[i] = *--basesp;
560 /* read unused callee saved flt regs */
563 for (i=0; count > code->savedfltcount; ++i) {
564 assert(i < FLT_REG_CNT);
565 if (nregdescfloat[i] == REG_SAV)
566 ss->savedfltregs[--count] = es->fltregs[i];
569 /* read saved flt regs */
571 for (i=0; i<code->savedfltcount; ++i) {
572 #ifdef HAS_4BYTE_STACKSLOT
577 ss->savedfltregs[i] = *(u8*)basesp;
580 /* read slots used for synchronization */
582 count = code_get_sync_slot_count(code);
583 ss->syncslotcount = count;
584 ss->syncslots = DMNEW(u8,count);
585 for (i=0; i<count; ++i) {
586 ss->syncslots[i] = sp[code->memuse + i];
590 /* replace_write_executionstate ************************************************
592 Translate the given source state into an execution state.
595 rp...............replacement point for which execution state should be
597 es...............where to put the execution state
598 ss...............the given source state
601 *es..............the execution state derived from the source state
603 *******************************************************************************/
605 static void replace_write_executionstate(rplpoint *rp,executionstate *es,
617 #ifdef HAS_4BYTE_STACKSLOT
628 topslot = TOP_IS_NORMAL;
630 /* calculate stack pointer */
632 #ifdef HAS_4BYTE_STACKSLOT
633 basesp = (u4*) ss->stackbase;
635 basesp = (u8*) ss->stackbase;
638 sp = basesp - code_get_stack_frame_size(code);
640 /* on some architectures the returnAddress is passed on the stack by JSR */
642 #if defined(__I386__) || defined(__X86_64__)
643 if (rp->type == BBTYPE_SBR) {
644 topslot = TOP_IS_ON_STACK;
648 /* in some cases the top stack slot is passed in REG_ITMP1 */
650 if ( (rp->type == BBTYPE_EXH)
651 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)
652 || (rp->type == BBTYPE_SBR)
656 topslot = TOP_IS_IN_ITMP1;
659 /* in debug mode, invalidate stack frame first */
662 for (i=0; i<(basesp - sp); ++i) {
667 /* write local variables */
669 count = m->maxlocals;
674 for (allocs = code->globalcount; allocs--; ra++) {
678 assert(i >= 0 && i < m->maxlocals);
682 continue; /* dummy rplalloc */
684 replace_write_value(es,sp,ra,ss->javalocals + (5*i+t));
687 /* write stack slots */
689 count = rp->regalloccount;
694 /* the first stack slot is special in SBR and EXH blocks */
696 if (topslot == TOP_IS_ON_STACK) {
699 sp[-1] = ss->javastack[i];
704 else if (topslot == TOP_IS_IN_ITMP1) {
707 es->intregs[REG_ITMP1] = ss->javastack[i];
713 /* write remaining stack slots */
715 for (; count--; ra++, i++) {
718 replace_write_value(es,sp,ra,ss->javastack + i);
721 /* write unused callee saved int regs */
724 for (i=0; count > code->savedintcount; ++i) {
725 assert(i < INT_REG_CNT);
726 if (nregdescint[i] == REG_SAV)
727 es->intregs[i] = ss->savedintregs[--count];
730 /* write saved int regs */
732 for (i=0; i<code->savedintcount; ++i) {
733 *--basesp = ss->savedintregs[i];
736 /* write unused callee saved flt regs */
739 for (i=0; count > code->savedfltcount; ++i) {
740 assert(i < FLT_REG_CNT);
741 if (nregdescfloat[i] == REG_SAV)
742 es->fltregs[i] = ss->savedfltregs[--count];
745 /* write saved flt regs */
747 for (i=0; i<code->savedfltcount; ++i) {
748 #ifdef HAS_4BYTE_STACKSLOT
753 *(u8*)basesp = ss->savedfltregs[i];
756 /* write slots used for synchronization */
758 count = code_get_sync_slot_count(code);
759 assert(count == ss->syncslotcount);
760 for (i=0; i<count; ++i) {
761 sp[code->memuse + i] = ss->syncslots[i];
769 /* replace_me ******************************************************************
771 This function is called by asm_replacement_out when a thread reaches
772 a replacement point. `replace_me` must map the execution state to the
773 target replacement point and let execution continue there.
775 This function never returns!
778 rp...............replacement point that has been reached
779 es...............execution state read by asm_replacement_out
781 *******************************************************************************/
783 void replace_me(rplpoint *rp,executionstate *es)
789 /* mark start of dump memory area */
791 dumpsize = dump_size();
793 /* fetch the target of the replacement */
797 /* XXX DEBUG turn off self-replacement */
799 replace_deactivate_replacement_point(rp);
802 printf("replace_me(%p,%p)\n",(void*)rp,(void*)es);
804 replace_replacement_point_println(rp);
805 replace_executionstate_println(es,rp->code);
808 /* read execution state of old code */
810 replace_read_executionstate(rp,es,&ss);
813 replace_sourcestate_println(&ss);
816 /* write execution state of new code */
818 replace_write_executionstate(target,es,&ss);
821 replace_executionstate_println(es,target->code);
824 /* release dump area */
826 dump_release(dumpsize);
830 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
831 asm_replacement_in(es);
836 /* replace_replacement_point_println *******************************************
838 Print replacement point info.
841 rp...............the replacement point to print
843 *******************************************************************************/
846 static const char *type_char = "IJFDA";
848 #define TYPECHAR(t) (((t) >= 0 && (t) <= 4) ? type_char[t] : '?')
850 void replace_replacement_point_println(rplpoint *rp)
855 printf("(rplpoint *)NULL\n");
859 printf("rplpoint %p pc:%p out:%p target:%p mcode:%016llx type:%01d flags:%01x ra:%d = [",
860 (void*)rp,rp->pc,rp->outcode,(void*)rp->target,
861 (unsigned long long)rp->mcode,rp->type,rp->flags,rp->regalloccount);
863 for (j=0; j<rp->regalloccount; ++j)
864 printf("%c%1c%01x:%02d",
865 (rp->regalloc[j].next) ? '^' : ' ',
866 TYPECHAR(rp->regalloc[j].type),
867 rp->regalloc[j].flags,
868 rp->regalloc[j].index);
870 printf("]\n method: ");
871 method_print(rp->code->m);
877 /* replace_show_replacement_points *********************************************
879 Print replacement point info.
882 code.............codeinfo whose replacement points should be printed.
884 *******************************************************************************/
887 void replace_show_replacement_points(codeinfo *code)
893 printf("(codeinfo *)NULL\n");
897 printf("\treplacement points: %d\n",code->rplpointcount);
898 printf("\tglobal allocations: %d = [",code->globalcount);
900 for (i=0; i<code->globalcount; ++i)
901 printf("%c%1c%01x:%02d",
902 (code->regalloc[i].next) ? '^' : ' ',
903 TYPECHAR(code->regalloc[i].type),
904 code->regalloc[i].flags,code->regalloc[i].index);
908 printf("\ttotal allocations : %d\n",code->regalloccount);
909 printf("\tsaved int regs : %d\n",code->savedintcount);
910 printf("\tsaved flt regs : %d\n",code->savedfltcount);
911 printf("\tmemuse : %d\n",code->memuse);
915 for (i=0; i<code->rplpointcount; ++i) {
916 rp = code->rplpoints + i;
918 assert(rp->code == code);
921 replace_replacement_point_println(rp);
926 /* replace_executionstate_println **********************************************
928 Print execution state
931 es...............the execution state to print
932 code.............the codeinfo for which this execution state is meant
935 *******************************************************************************/
938 void replace_executionstate_println(executionstate *es,codeinfo *code)
942 #ifdef HAS_4BYTE_STACKSLOT
949 printf("(executionstate *)NULL\n");
953 printf("executionstate %p:\n",(void*)es);
954 printf("\tpc = %p\n",(void*)es->pc);
955 printf("\tsp = %p\n",(void*)es->sp);
956 printf("\tpv = %p\n",(void*)es->pv);
957 #if defined(ENABLE_DISASSEMBLER)
958 for (i=0; i<INT_REG_CNT; ++i) {
959 printf("\t%-3s = %016llx\n",regs[i],(unsigned long long)es->intregs[i]);
961 for (i=0; i<FLT_REG_CNT; ++i) {
962 printf("\tfltregs[%2d] = %016llx\n",i,(unsigned long long)es->fltregs[i]);
966 #ifdef HAS_4BYTE_STACKSLOT
973 slots = code_get_stack_frame_size(code);
977 printf("\tstack slots at sp:\n");
978 for (i=0; i<slots; ++i) {
979 #ifdef HAS_4BYTE_STACKSLOT
980 printf("\t\t%08lx\n",(unsigned long)*sp++);
982 printf("\t\t%016llx\n",(unsigned long long)*sp++);
990 /* replace_sourcestate_println *************************************************
995 ss...............the source state to print
997 *******************************************************************************/
1000 void replace_sourcestate_println(sourcestate *ss)
1007 printf("(sourcestate *)NULL\n");
1011 printf("sourcestate %p: stackbase=%p\n",(void*)ss,(void*)ss->stackbase);
1013 printf("\tlocals (%d):\n",ss->javalocalcount);
1014 for (i=0; i<ss->javalocalcount; ++i) {
1015 for (t=0; t<5; ++t) {
1016 if (ss->javalocals[i*5+t] != 0x00dead0000dead00ULL) {
1017 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
1018 printf("%016llx\n",(unsigned long long) ss->javalocals[i*5+t]);
1025 printf("\tstack (depth %d):\n",ss->javastackdepth);
1026 for (i=0; i<ss->javastackdepth; ++i) {
1027 printf("\tstack[%2d] = ",i);
1028 printf("%016llx\n",(unsigned long long) ss->javastack[i]);
1033 printf("\tsaved int registers (%d):\n",INT_SAV_CNT);
1035 for (i=0; i<INT_SAV_CNT; ++i) {
1036 while (nregdescint[--reg] != REG_SAV)
1038 if (ss->savedintregs[i] != 0x00dead0000dead00ULL) {
1039 #if defined(ENABLE_DISASSEMBLER)
1040 printf("\t%-3s = ",regs[reg]);
1042 printf("%016llx\n",(unsigned long long) ss->savedintregs[i]);
1048 printf("\tsaved float registers (%d):\n",FLT_SAV_CNT);
1049 for (i=0; i<FLT_SAV_CNT; ++i) {
1050 if (ss->savedfltregs[i] != 0x00dead0000dead00ULL) {
1051 printf("\tsavedfltreg[%2d] = ",i);
1052 printf("%016llx\n",(unsigned long long) ss->savedfltregs[i]);
1058 printf("\tsynchronization slots (%d):\n",ss->syncslotcount);
1059 for (i=0; i<ss->syncslotcount; ++i) {
1060 printf("\tslot[%2d] = ",i);
1061 #ifdef HAS_4BYTE_STACKSLOT
1062 printf("%08lx\n",(unsigned long) ss->syncslots[i]);
1064 printf("%016llx\n",(unsigned long long) ss->syncslots[i]);
1073 * These are local overrides for various environment variables in Emacs.
1074 * Please do not remove this and leave it at the end of the file, where
1075 * Emacs will automagically detect them.
1076 * ---------------------------------------------------------------------
1079 * indent-tabs-mode: t
1083 * vim:noexpandtab:sw=4:ts=4: