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
41 #include "mm/memory.h"
42 #include "toolbox/logging.h"
43 #include "vm/options.h"
44 #include "vm/jit/jit.h"
45 #include "vm/jit/replace.h"
46 #include "vm/jit/asmpart.h"
47 #include "vm/jit/disass.h"
50 /*** constants used internally ************************************************/
52 #define TOP_IS_NORMAL 0
53 #define TOP_IS_ON_STACK 1
54 #define TOP_IS_IN_ITMP1 2
56 /* replace_create_replacement_points *******************************************
58 Create the replacement points for the given code.
61 code.............codeinfo where replacement points should be stored
62 code->rplpoints must be NULL.
63 code->rplpointcount must be 0.
64 rd...............registerdata containing allocation info.
67 code->rplpoints.......set to the list of replacement points
68 code->rplpointcount...number of replacement points
69 code->regalloc........list of allocation info
70 code->regalloccount...total length of allocation info list
71 code->globalcount.....number of global allocations at the
72 start of code->regalloc
75 true.............everything ok
76 false............an exception has been thrown
78 *******************************************************************************/
80 bool replace_create_replacement_points(codeinfo *code,registerdata *rd)
96 /* assert that we wont overwrite already allocated data */
100 assert(code->rplpoints == NULL);
101 assert(code->rplpointcount == 0);
102 assert(code->regalloc == NULL);
103 assert(code->regalloccount == 0);
104 assert(code->globalcount == 0);
106 /* iterate over the basic block list to find replacement points */
112 for (bptr = m->basicblocks; bptr; bptr = bptr->next) {
113 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
116 /* there will be a replacement point at the start of this block */
119 alloccount += bptr->indepth;
122 /* if no points were found, there's nothing to do */
127 /* count global register allocations */
131 for (i=0; i<m->maxlocals; ++i) {
133 for (t=0; t<5; ++t) {
134 #if defined(ENABLE_INTRP)
137 if (rd->locals[i][t].type == t) {
141 #if defined(ENABLE_INTRP)
146 globalcount++; /* dummy rplalloc */
149 alloccount += globalcount;
151 /* allocate replacement point array and allocation array */
153 rplpoints = MNEW(rplpoint,count);
154 regalloc = MNEW(rplalloc,alloccount);
157 /* store global register allocations */
159 for (i=0; i<m->maxlocals; ++i) {
161 for (t=0; t<5; ++t) {
162 #if defined(ENABLE_INTRP)
165 if (rd->locals[i][t].type == t) {
166 ra->flags = rd->locals[i][t].flags & (INMEMORY);
167 ra->index = rd->locals[i][t].regoff;
169 ra->next = (indexused) ? 0 : 1;
173 #if defined(ENABLE_INTRP)
187 /* initialize replacement point structs */
190 for (bptr = m->basicblocks; bptr; bptr = bptr->next) {
191 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
194 /* there will be a replacement point at the start of this block */
196 rp->pc = NULL; /* set by codegen */
197 rp->outcode = NULL; /* set by codegen */
202 rp->type = bptr->type;
204 /* store local allocation info */
206 for (sp = bptr->instack; sp; sp = sp->prev) {
207 ra->flags = sp->flags & (INMEMORY);
208 ra->index = sp->regoff;
214 rp->regalloccount = ra - rp->regalloc;
219 /* store the data in the codeinfo */
221 code->rplpoints = rplpoints;
222 code->rplpointcount = count;
223 code->regalloc = regalloc;
224 code->regalloccount = alloccount;
225 code->globalcount = globalcount;
226 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
227 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
228 code->memuse = rd->memuse;
229 code->isleafmethod = m->isleafmethod; /* XXX will be moved to codeinfo */
231 /* everything alright */
236 /* replace_free_replacement_points *********************************************
238 Free memory used by replacement points.
241 code.............codeinfo whose replacement points should be freed.
243 *******************************************************************************/
245 void replace_free_replacement_points(codeinfo *code)
250 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
253 MFREE(code->regalloc,rplalloc,code->regalloccount);
255 code->rplpoints = NULL;
256 code->rplpointcount = 0;
257 code->regalloc = NULL;
258 code->regalloccount = 0;
259 code->globalcount = 0;
262 /* replace_activate_replacement_point ******************************************
264 Activate a replacement point. When this function returns, the
265 replacement point is "armed", that is each thread reaching this point
266 will be replace to `target`.
269 rp...............replacement point to activate
270 target...........target of replacement
272 *******************************************************************************/
274 void replace_activate_replacement_point(rplpoint *rp,rplpoint *target)
276 assert(rp->target == NULL);
279 printf("activate replacement point: ");
280 replace_replacement_point_println(rp);
286 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
287 md_patch_replacement_point(rp);
291 /* replace_deactivate_replacement_point ****************************************
293 Deactivate a replacement point. When this function returns, the
294 replacement point is "un-armed", that is a each thread reaching this point
295 will just continue normally.
298 rp...............replacement point to deactivate
300 *******************************************************************************/
302 void replace_deactivate_replacement_point(rplpoint *rp)
307 printf("deactivate replacement point: ");
308 replace_replacement_point_println(rp);
314 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
315 md_patch_replacement_point(rp);
319 /* replace_read_executionstate *************************************************
321 Read the given executions state and translate it to a source state.
324 rp...............replacement point at which `es` was taken
325 es...............execution state
326 ss...............where to put the source state
329 *ss..............the source state derived from the execution state
331 *******************************************************************************/
333 inline static void replace_read_value(executionstate *es,
334 #ifdef HAS_4BYTE_STACKSLOT
342 if (ra->flags & INMEMORY) {
343 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
344 #ifdef HAS_4BYTE_STACKSLOT
345 if (IS_2_WORD_TYPE(ra->type)) {
346 *javaval = *(u8*)(sp + ra->index);
350 *javaval = sp[ra->index];
351 #ifdef HAS_4BYTE_STACKSLOT
356 /* allocated register */
357 if (IS_FLT_DBL_TYPE(ra->type)) {
358 *javaval = es->fltregs[ra->index];
361 *javaval = es->intregs[ra->index];
366 inline static void replace_write_value(executionstate *es,
367 #ifdef HAS_4BYTE_STACKSLOT
375 if (ra->flags & INMEMORY) {
376 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
377 #ifdef HAS_4BYTE_STACKSLOT
378 if (IS_2_WORD_TYPE(ra->type)) {
379 *(u8*)(sp + ra->index) = *javaval;
383 sp[ra->index] = *javaval;
384 #ifdef HAS_4BYTE_STACKSLOT
389 /* allocated register */
390 if (IS_FLT_DBL_TYPE(ra->type)) {
391 es->fltregs[ra->index] = *javaval;
394 es->intregs[ra->index] = *javaval;
399 static void replace_read_executionstate(rplpoint *rp,executionstate *es,
411 #ifdef HAS_4BYTE_STACKSLOT
422 topslot = TOP_IS_NORMAL;
426 #ifdef HAS_4BYTE_STACKSLOT
432 /* on some architectures the returnAddress is passed on the stack by JSR */
434 #if defined(__I386__) || defined(__X86_64__)
435 if (rp->type == BBTYPE_SBR) {
437 topslot = TOP_IS_ON_STACK;
441 /* in some cases the top stack slot is passed in REG_ITMP1 */
443 if ( (rp->type == BBTYPE_EXH)
444 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)
445 || (rp->type == BBTYPE_SBR)
449 topslot = TOP_IS_IN_ITMP1;
452 /* calculate base stack pointer */
454 basesp = sp + code_get_stack_frame_size(code);
456 ss->stackbase = (u1*) basesp;
458 /* read local variables */
460 count = m->maxlocals;
461 ss->javalocalcount = count;
462 ss->javalocals = DMNEW(u8,count * 5);
465 /* mark values as undefined */
466 for (i=0; i<count*5; ++i)
467 ss->javalocals[i] = (u8) 0x00dead0000dead00ULL;
469 /* some entries in the intregs array are not meaningful */
470 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
471 es->intregs[REG_SP ] = (u8) 0x11dead1111dead11ULL;
473 es->intregs[REG_PV ] = (u8) 0x11dead1111dead11ULL;
480 for (allocs = code->globalcount; allocs--; ra++) {
485 continue; /* dummy rplalloc */
487 replace_read_value(es,sp,ra,ss->javalocals + (5*i+t));
490 /* read stack slots */
492 count = rp->regalloccount;
493 ss->javastackdepth = count;
494 ss->javastack = DMNEW(u8,count);
497 /* mark values as undefined */
498 for (i=0; i<count; ++i)
499 ss->javastack[i] = (u8) 0x00dead0000dead00ULL;
505 /* the first stack slot is special in SBR and EXH blocks */
507 if (topslot == TOP_IS_ON_STACK) {
510 ss->javastack[i] = sp[-1];
515 else if (topslot == TOP_IS_IN_ITMP1) {
518 ss->javastack[i] = es->intregs[REG_ITMP1];
524 /* read remaining stack slots */
526 for (; count--; ra++, i++) {
529 replace_read_value(es,sp,ra,ss->javastack + i);
532 /* read unused callee saved int regs */
535 for (i=0; count > code->savedintcount; ++i) {
536 assert(i < INT_REG_CNT);
537 if (nregdescint[i] == REG_SAV)
538 ss->savedintregs[--count] = es->intregs[i];
541 /* read saved int regs */
543 for (i=0; i<code->savedintcount; ++i) {
544 ss->savedintregs[i] = *--basesp;
547 /* read unused callee saved flt regs */
550 for (i=0; count > code->savedfltcount; ++i) {
551 assert(i < FLT_REG_CNT);
552 if (nregdescfloat[i] == REG_SAV)
553 ss->savedfltregs[--count] = es->fltregs[i];
556 /* read saved flt regs */
558 for (i=0; i<code->savedfltcount; ++i) {
559 #ifdef HAS_4BYTE_STACKSLOT
564 ss->savedfltregs[i] = *(u8*)basesp;
567 /* read slots used for synchronization */
569 count = code_get_sync_slot_count(code);
570 ss->syncslotcount = count;
571 ss->syncslots = DMNEW(u8,count);
572 for (i=0; i<count; ++i) {
573 ss->syncslots[i] = sp[code->memuse + i];
577 /* replace_write_executionstate ************************************************
579 Translate the given source state into an execution state.
582 rp...............replacement point for which execution state should be
584 es...............where to put the execution state
585 ss...............the given source state
588 *es..............the execution state derived from the source state
590 *******************************************************************************/
592 static void replace_write_executionstate(rplpoint *rp,executionstate *es,
604 #ifdef HAS_4BYTE_STACKSLOT
615 topslot = TOP_IS_NORMAL;
617 /* calculate stack pointer */
619 #ifdef HAS_4BYTE_STACKSLOT
620 basesp = (u4*) ss->stackbase;
622 basesp = (u8*) ss->stackbase;
625 sp = basesp - code_get_stack_frame_size(code);
627 /* on some architectures the returnAddress is passed on the stack by JSR */
629 #if defined(__I386__) || defined(__X86_64__)
630 if (rp->type == BBTYPE_SBR) {
631 topslot = TOP_IS_ON_STACK;
635 /* in some cases the top stack slot is passed in REG_ITMP1 */
637 if ( (rp->type == BBTYPE_EXH)
638 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)
639 || (rp->type == BBTYPE_SBR)
643 topslot = TOP_IS_IN_ITMP1;
646 /* in debug mode, invalidate stack frame first */
649 for (i=0; i<(basesp - sp); ++i) {
654 /* write local variables */
656 count = m->maxlocals;
661 for (allocs = code->globalcount; allocs--; ra++) {
665 assert(i >= 0 && i < m->maxlocals);
669 continue; /* dummy rplalloc */
671 replace_write_value(es,sp,ra,ss->javalocals + (5*i+t));
674 /* write stack slots */
676 count = rp->regalloccount;
681 /* the first stack slot is special in SBR and EXH blocks */
683 if (topslot == TOP_IS_ON_STACK) {
686 sp[-1] = ss->javastack[i];
691 else if (topslot == TOP_IS_IN_ITMP1) {
694 es->intregs[REG_ITMP1] = ss->javastack[i];
700 /* write remaining stack slots */
702 for (; count--; ra++, i++) {
705 replace_write_value(es,sp,ra,ss->javastack + i);
708 /* write unused callee saved int regs */
711 for (i=0; count > code->savedintcount; ++i) {
712 assert(i < INT_REG_CNT);
713 if (nregdescint[i] == REG_SAV)
714 es->intregs[i] = ss->savedintregs[--count];
717 /* write saved int regs */
719 for (i=0; i<code->savedintcount; ++i) {
720 *--basesp = ss->savedintregs[i];
723 /* write unused callee saved flt regs */
726 for (i=0; count > code->savedfltcount; ++i) {
727 assert(i < FLT_REG_CNT);
728 if (nregdescfloat[i] == REG_SAV)
729 es->fltregs[i] = ss->savedfltregs[--count];
732 /* write saved flt regs */
734 for (i=0; i<code->savedfltcount; ++i) {
735 #ifdef HAS_4BYTE_STACKSLOT
740 *(u8*)basesp = ss->savedfltregs[i];
743 /* write slots used for synchronization */
745 count = code_get_sync_slot_count(code);
746 assert(count == ss->syncslotcount);
747 for (i=0; i<count; ++i) {
748 sp[code->memuse + i] = ss->syncslots[i];
756 /* replace_me ******************************************************************
758 This function is called by asm_replacement_out when a thread reaches
759 a replacement point. `replace_me` must map the execution state to the
760 target replacement point and let execution continue there.
762 This function never returns!
765 rp...............replacement point that has been reached
766 es...............execution state read by asm_replacement_out
768 *******************************************************************************/
770 void replace_me(rplpoint *rp,executionstate *es)
776 /* mark start of dump memory area */
778 dumpsize = dump_size();
780 /* fetch the target of the replacement */
784 /* XXX DEBUG turn of self-replacement */
786 replace_deactivate_replacement_point(rp);
789 printf("replace_me(%p,%p)\n",(void*)rp,(void*)es);
791 replace_replacement_point_println(rp);
792 replace_executionstate_println(es,rp->code);
795 /* read execution state of old code */
797 replace_read_executionstate(rp,es,&ss);
800 replace_sourcestate_println(&ss);
803 /* write execution state of new code */
805 replace_write_executionstate(target,es,&ss);
808 replace_executionstate_println(es,target->code);
811 /* release dump area */
813 dump_release(dumpsize);
817 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
818 asm_replacement_in(es);
823 /* replace_replacement_point_println *******************************************
825 Print replacement point info.
828 rp...............the replacement point to print
830 *******************************************************************************/
833 static const char *type_char = "IJFDA";
835 #define TYPECHAR(t) (((t) >= 0 && (t) <= 4) ? type_char[t] : '?')
837 void replace_replacement_point_println(rplpoint *rp)
842 printf("(rplpoint *)NULL\n");
846 printf("rplpoint %p pc:%p out:%p target:%p mcode:%016llx type:%01d flags:%01x ra:%d = [",
847 (void*)rp,rp->pc,rp->outcode,(void*)rp->target,
848 (unsigned long long)rp->mcode,rp->type,rp->flags,rp->regalloccount);
850 for (j=0; j<rp->regalloccount; ++j)
851 printf("%c%1c%01x:%02d",
852 (rp->regalloc[j].next) ? '^' : ' ',
853 TYPECHAR(rp->regalloc[j].type),
854 rp->regalloc[j].flags,
855 rp->regalloc[j].index);
857 printf("]\n method: ");
858 method_print(rp->code->m);
864 /* replace_show_replacement_points *********************************************
866 Print replacement point info.
869 code.............codeinfo whose replacement points should be printed.
871 *******************************************************************************/
874 void replace_show_replacement_points(codeinfo *code)
880 printf("(codeinfo *)NULL\n");
884 printf("\treplacement points: %d\n",code->rplpointcount);
885 printf("\tglobal allocations: %d = [",code->globalcount);
887 for (i=0; i<code->globalcount; ++i)
888 printf("%c%1c%01x:%02d",
889 (code->regalloc[i].next) ? '^' : ' ',
890 TYPECHAR(code->regalloc[i].type),
891 code->regalloc[i].flags,code->regalloc[i].index);
895 printf("\ttotal allocations : %d\n",code->regalloccount);
896 printf("\tsaved int regs : %d\n",code->savedintcount);
897 printf("\tsaved flt regs : %d\n",code->savedfltcount);
898 printf("\tmemuse : %d\n",code->memuse);
902 for (i=0; i<code->rplpointcount; ++i) {
903 rp = code->rplpoints + i;
905 assert(rp->code == code);
908 replace_replacement_point_println(rp);
913 /* replace_executionstate_println **********************************************
915 Print execution state
918 es...............the execution state to print
919 code.............the codeinfo for which this execution state is meant
922 *******************************************************************************/
925 void replace_executionstate_println(executionstate *es,codeinfo *code)
929 #ifdef HAS_4BYTE_STACKSLOT
936 printf("(executionstate *)NULL\n");
940 printf("executionstate %p:\n",(void*)es);
941 printf("\tpc = %p\n",(void*)es->pc);
942 printf("\tsp = %p\n",(void*)es->sp);
943 printf("\tpv = %p\n",(void*)es->pv);
944 for (i=0; i<INT_REG_CNT; ++i) {
945 printf("\t%-3s = %016llx\n",regs[i],(unsigned long long)es->intregs[i]);
947 for (i=0; i<FLT_REG_CNT; ++i) {
948 printf("\tfltregs[%2d] = %016llx\n",i,(unsigned long long)es->fltregs[i]);
951 #ifdef HAS_4BYTE_STACKSLOT
958 slots = code_get_stack_frame_size(code);
962 printf("\tstack slots at sp:\n");
963 for (i=0; i<slots; ++i) {
964 #ifdef HAS_4BYTE_STACKSLOT
965 printf("\t\t%08lx\n",(unsigned long)*sp++);
967 printf("\t\t%016llx\n",(unsigned long long)*sp++);
975 /* replace_sourcestate_println *************************************************
980 ss...............the source state to print
982 *******************************************************************************/
985 void replace_sourcestate_println(sourcestate *ss)
992 printf("(sourcestate *)NULL\n");
996 printf("sourcestate %p: stackbase=%p\n",(void*)ss,(void*)ss->stackbase);
998 printf("\tlocals (%d):\n",ss->javalocalcount);
999 for (i=0; i<ss->javalocalcount; ++i) {
1000 for (t=0; t<5; ++t) {
1001 if (ss->javalocals[i*5+t] != 0x00dead0000dead00ULL) {
1002 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
1003 printf("%016llx\n",(unsigned long long) ss->javalocals[i*5+t]);
1010 printf("\tstack (depth %d):\n",ss->javastackdepth);
1011 for (i=0; i<ss->javastackdepth; ++i) {
1012 printf("\tstack[%2d] = ",i);
1013 printf("%016llx\n",(unsigned long long) ss->javastack[i]);
1018 printf("\tsaved int registers (%d):\n",INT_SAV_CNT);
1020 for (i=0; i<INT_SAV_CNT; ++i) {
1021 while (nregdescint[--reg] != REG_SAV)
1023 if (ss->savedintregs[i] != 0x00dead0000dead00ULL) {
1024 printf("\t%-3s = ",regs[reg]);
1025 printf("%016llx\n",(unsigned long long) ss->savedintregs[i]);
1031 printf("\tsaved float registers (%d):\n",FLT_SAV_CNT);
1032 for (i=0; i<FLT_SAV_CNT; ++i) {
1033 if (ss->savedfltregs[i] != 0x00dead0000dead00ULL) {
1034 printf("\tsavedfltreg[%2d] = ",i);
1035 printf("%016llx\n",(unsigned long long) ss->savedfltregs[i]);
1041 printf("\tsynchronization slots (%d):\n",ss->syncslotcount);
1042 for (i=0; i<ss->syncslotcount; ++i) {
1043 printf("\tslot[%2d] = ",i);
1044 #ifdef HAS_4BYTE_STACKSLOT
1045 printf("%08lx\n",(unsigned long) ss->syncslots[i]);
1047 printf("%016llx\n",(unsigned long long) ss->syncslots[i]);
1056 * These are local overrides for various environment variables in Emacs.
1057 * Please do not remove this and leave it at the end of the file, where
1058 * Emacs will automagically detect them.
1059 * ---------------------------------------------------------------------
1062 * indent-tabs-mode: t
1066 * vim:noexpandtab:sw=4:ts=4: