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)
101 /* get required compiler data */
106 /* assert that we wont overwrite already allocated data */
110 assert(code->rplpoints == NULL);
111 assert(code->rplpointcount == 0);
112 assert(code->regalloc == NULL);
113 assert(code->regalloccount == 0);
114 assert(code->globalcount == 0);
116 /* iterate over the basic block list to find replacement points */
122 for (bptr = m->basicblocks; bptr; bptr = bptr->next) {
123 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
126 /* there will be a replacement point at the start of this block */
129 alloccount += bptr->indepth;
132 /* if no points were found, there's nothing to do */
137 /* count global register allocations */
141 for (i=0; i<m->maxlocals; ++i) {
143 for (t=0; t<5; ++t) {
144 #if defined(ENABLE_INTRP)
147 if (rd->locals[i][t].type == t) {
151 #if defined(ENABLE_INTRP)
156 globalcount++; /* dummy rplalloc */
159 alloccount += globalcount;
161 /* allocate replacement point array and allocation array */
163 rplpoints = MNEW(rplpoint,count);
164 regalloc = MNEW(rplalloc,alloccount);
167 /* store global register allocations */
169 for (i=0; i<m->maxlocals; ++i) {
171 for (t=0; t<5; ++t) {
172 #if defined(ENABLE_INTRP)
175 if (rd->locals[i][t].type == t) {
176 ra->flags = rd->locals[i][t].flags & (INMEMORY);
177 ra->index = rd->locals[i][t].regoff;
179 ra->next = (indexused) ? 0 : 1;
183 #if defined(ENABLE_INTRP)
197 /* initialize replacement point structs */
200 for (bptr = m->basicblocks; bptr; bptr = bptr->next) {
201 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
204 /* there will be a replacement point at the start of this block */
206 rp->pc = NULL; /* set by codegen */
207 rp->outcode = NULL; /* set by codegen */
212 rp->type = bptr->type;
214 /* store local allocation info */
216 for (sp = bptr->instack; sp; sp = sp->prev) {
217 ra->flags = sp->flags & (INMEMORY);
218 ra->index = sp->regoff;
224 rp->regalloccount = ra - rp->regalloc;
229 /* store the data in the codeinfo */
231 code->rplpoints = rplpoints;
232 code->rplpointcount = count;
233 code->regalloc = regalloc;
234 code->regalloccount = alloccount;
235 code->globalcount = globalcount;
236 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
237 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
238 code->memuse = rd->memuse;
239 code->isleafmethod = m->isleafmethod; /* XXX will be moved to codeinfo */
241 /* everything alright */
246 /* replace_free_replacement_points *********************************************
248 Free memory used by replacement points.
251 code.............codeinfo whose replacement points should be freed.
253 *******************************************************************************/
255 void replace_free_replacement_points(codeinfo *code)
260 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
263 MFREE(code->regalloc,rplalloc,code->regalloccount);
265 code->rplpoints = NULL;
266 code->rplpointcount = 0;
267 code->regalloc = NULL;
268 code->regalloccount = 0;
269 code->globalcount = 0;
272 /* replace_activate_replacement_point ******************************************
274 Activate a replacement point. When this function returns, the
275 replacement point is "armed", that is each thread reaching this point
276 will be replace to `target`.
279 rp...............replacement point to activate
280 target...........target of replacement
282 *******************************************************************************/
284 void replace_activate_replacement_point(rplpoint *rp,rplpoint *target)
286 assert(rp->target == NULL);
289 printf("activate replacement point: ");
290 replace_replacement_point_println(rp);
296 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
297 md_patch_replacement_point(rp);
301 /* replace_deactivate_replacement_point ****************************************
303 Deactivate a replacement point. When this function returns, the
304 replacement point is "un-armed", that is a each thread reaching this point
305 will just continue normally.
308 rp...............replacement point to deactivate
310 *******************************************************************************/
312 void replace_deactivate_replacement_point(rplpoint *rp)
317 printf("deactivate replacement point: ");
318 replace_replacement_point_println(rp);
324 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
325 md_patch_replacement_point(rp);
329 /* replace_read_executionstate *************************************************
331 Read the given executions state and translate it to a source state.
334 rp...............replacement point at which `es` was taken
335 es...............execution state
336 ss...............where to put the source state
339 *ss..............the source state derived from the execution state
341 *******************************************************************************/
343 inline static void replace_read_value(executionstate *es,
344 #ifdef HAS_4BYTE_STACKSLOT
352 if (ra->flags & INMEMORY) {
353 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
354 #ifdef HAS_4BYTE_STACKSLOT
355 if (IS_2_WORD_TYPE(ra->type)) {
356 *javaval = *(u8*)(sp + ra->index);
360 *javaval = sp[ra->index];
361 #ifdef HAS_4BYTE_STACKSLOT
366 /* allocated register */
367 if (IS_FLT_DBL_TYPE(ra->type)) {
368 *javaval = es->fltregs[ra->index];
371 *javaval = es->intregs[ra->index];
376 inline static void replace_write_value(executionstate *es,
377 #ifdef HAS_4BYTE_STACKSLOT
385 if (ra->flags & INMEMORY) {
386 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
387 #ifdef HAS_4BYTE_STACKSLOT
388 if (IS_2_WORD_TYPE(ra->type)) {
389 *(u8*)(sp + ra->index) = *javaval;
393 sp[ra->index] = *javaval;
394 #ifdef HAS_4BYTE_STACKSLOT
399 /* allocated register */
400 if (IS_FLT_DBL_TYPE(ra->type)) {
401 es->fltregs[ra->index] = *javaval;
404 es->intregs[ra->index] = *javaval;
409 static void replace_read_executionstate(rplpoint *rp,executionstate *es,
421 #ifdef HAS_4BYTE_STACKSLOT
432 topslot = TOP_IS_NORMAL;
436 #ifdef HAS_4BYTE_STACKSLOT
442 /* on some architectures the returnAddress is passed on the stack by JSR */
444 #if defined(__I386__) || defined(__X86_64__)
445 if (rp->type == BBTYPE_SBR) {
447 topslot = TOP_IS_ON_STACK;
451 /* in some cases the top stack slot is passed in REG_ITMP1 */
453 if ( (rp->type == BBTYPE_EXH)
454 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)
455 || (rp->type == BBTYPE_SBR)
459 topslot = TOP_IS_IN_ITMP1;
462 /* calculate base stack pointer */
464 basesp = sp + code_get_stack_frame_size(code);
466 ss->stackbase = (u1*) basesp;
468 /* read local variables */
470 count = m->maxlocals;
471 ss->javalocalcount = count;
472 ss->javalocals = DMNEW(u8,count * 5);
475 /* mark values as undefined */
476 for (i=0; i<count*5; ++i)
477 ss->javalocals[i] = (u8) 0x00dead0000dead00ULL;
479 /* some entries in the intregs array are not meaningful */
480 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
481 es->intregs[REG_SP ] = (u8) 0x11dead1111dead11ULL;
483 es->intregs[REG_PV ] = (u8) 0x11dead1111dead11ULL;
490 for (allocs = code->globalcount; allocs--; ra++) {
495 continue; /* dummy rplalloc */
497 replace_read_value(es,sp,ra,ss->javalocals + (5*i+t));
500 /* read stack slots */
502 count = rp->regalloccount;
503 ss->javastackdepth = count;
504 ss->javastack = DMNEW(u8,count);
507 /* mark values as undefined */
508 for (i=0; i<count; ++i)
509 ss->javastack[i] = (u8) 0x00dead0000dead00ULL;
515 /* the first stack slot is special in SBR and EXH blocks */
517 if (topslot == TOP_IS_ON_STACK) {
520 ss->javastack[i] = sp[-1];
525 else if (topslot == TOP_IS_IN_ITMP1) {
528 ss->javastack[i] = es->intregs[REG_ITMP1];
534 /* read remaining stack slots */
536 for (; count--; ra++, i++) {
539 replace_read_value(es,sp,ra,ss->javastack + i);
542 /* read unused callee saved int regs */
545 for (i=0; count > code->savedintcount; ++i) {
546 assert(i < INT_REG_CNT);
547 if (nregdescint[i] == REG_SAV)
548 ss->savedintregs[--count] = es->intregs[i];
551 /* read saved int regs */
553 for (i=0; i<code->savedintcount; ++i) {
554 ss->savedintregs[i] = *--basesp;
557 /* read unused callee saved flt regs */
560 for (i=0; count > code->savedfltcount; ++i) {
561 assert(i < FLT_REG_CNT);
562 if (nregdescfloat[i] == REG_SAV)
563 ss->savedfltregs[--count] = es->fltregs[i];
566 /* read saved flt regs */
568 for (i=0; i<code->savedfltcount; ++i) {
569 #ifdef HAS_4BYTE_STACKSLOT
574 ss->savedfltregs[i] = *(u8*)basesp;
577 /* read slots used for synchronization */
579 count = code_get_sync_slot_count(code);
580 ss->syncslotcount = count;
581 ss->syncslots = DMNEW(u8,count);
582 for (i=0; i<count; ++i) {
583 ss->syncslots[i] = sp[code->memuse + i];
587 /* replace_write_executionstate ************************************************
589 Translate the given source state into an execution state.
592 rp...............replacement point for which execution state should be
594 es...............where to put the execution state
595 ss...............the given source state
598 *es..............the execution state derived from the source state
600 *******************************************************************************/
602 static void replace_write_executionstate(rplpoint *rp,executionstate *es,
614 #ifdef HAS_4BYTE_STACKSLOT
625 topslot = TOP_IS_NORMAL;
627 /* calculate stack pointer */
629 #ifdef HAS_4BYTE_STACKSLOT
630 basesp = (u4*) ss->stackbase;
632 basesp = (u8*) ss->stackbase;
635 sp = basesp - code_get_stack_frame_size(code);
637 /* on some architectures the returnAddress is passed on the stack by JSR */
639 #if defined(__I386__) || defined(__X86_64__)
640 if (rp->type == BBTYPE_SBR) {
641 topslot = TOP_IS_ON_STACK;
645 /* in some cases the top stack slot is passed in REG_ITMP1 */
647 if ( (rp->type == BBTYPE_EXH)
648 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)
649 || (rp->type == BBTYPE_SBR)
653 topslot = TOP_IS_IN_ITMP1;
656 /* in debug mode, invalidate stack frame first */
659 for (i=0; i<(basesp - sp); ++i) {
664 /* write local variables */
666 count = m->maxlocals;
671 for (allocs = code->globalcount; allocs--; ra++) {
675 assert(i >= 0 && i < m->maxlocals);
679 continue; /* dummy rplalloc */
681 replace_write_value(es,sp,ra,ss->javalocals + (5*i+t));
684 /* write stack slots */
686 count = rp->regalloccount;
691 /* the first stack slot is special in SBR and EXH blocks */
693 if (topslot == TOP_IS_ON_STACK) {
696 sp[-1] = ss->javastack[i];
701 else if (topslot == TOP_IS_IN_ITMP1) {
704 es->intregs[REG_ITMP1] = ss->javastack[i];
710 /* write remaining stack slots */
712 for (; count--; ra++, i++) {
715 replace_write_value(es,sp,ra,ss->javastack + i);
718 /* write unused callee saved int regs */
721 for (i=0; count > code->savedintcount; ++i) {
722 assert(i < INT_REG_CNT);
723 if (nregdescint[i] == REG_SAV)
724 es->intregs[i] = ss->savedintregs[--count];
727 /* write saved int regs */
729 for (i=0; i<code->savedintcount; ++i) {
730 *--basesp = ss->savedintregs[i];
733 /* write unused callee saved flt regs */
736 for (i=0; count > code->savedfltcount; ++i) {
737 assert(i < FLT_REG_CNT);
738 if (nregdescfloat[i] == REG_SAV)
739 es->fltregs[i] = ss->savedfltregs[--count];
742 /* write saved flt regs */
744 for (i=0; i<code->savedfltcount; ++i) {
745 #ifdef HAS_4BYTE_STACKSLOT
750 *(u8*)basesp = ss->savedfltregs[i];
753 /* write slots used for synchronization */
755 count = code_get_sync_slot_count(code);
756 assert(count == ss->syncslotcount);
757 for (i=0; i<count; ++i) {
758 sp[code->memuse + i] = ss->syncslots[i];
766 /* replace_me ******************************************************************
768 This function is called by asm_replacement_out when a thread reaches
769 a replacement point. `replace_me` must map the execution state to the
770 target replacement point and let execution continue there.
772 This function never returns!
775 rp...............replacement point that has been reached
776 es...............execution state read by asm_replacement_out
778 *******************************************************************************/
780 void replace_me(rplpoint *rp,executionstate *es)
786 /* mark start of dump memory area */
788 dumpsize = dump_size();
790 /* fetch the target of the replacement */
794 /* XXX DEBUG turn of self-replacement */
796 replace_deactivate_replacement_point(rp);
799 printf("replace_me(%p,%p)\n",(void*)rp,(void*)es);
801 replace_replacement_point_println(rp);
802 replace_executionstate_println(es,rp->code);
805 /* read execution state of old code */
807 replace_read_executionstate(rp,es,&ss);
810 replace_sourcestate_println(&ss);
813 /* write execution state of new code */
815 replace_write_executionstate(target,es,&ss);
818 replace_executionstate_println(es,target->code);
821 /* release dump area */
823 dump_release(dumpsize);
827 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
828 asm_replacement_in(es);
833 /* replace_replacement_point_println *******************************************
835 Print replacement point info.
838 rp...............the replacement point to print
840 *******************************************************************************/
843 static const char *type_char = "IJFDA";
845 #define TYPECHAR(t) (((t) >= 0 && (t) <= 4) ? type_char[t] : '?')
847 void replace_replacement_point_println(rplpoint *rp)
852 printf("(rplpoint *)NULL\n");
856 printf("rplpoint %p pc:%p out:%p target:%p mcode:%016llx type:%01d flags:%01x ra:%d = [",
857 (void*)rp,rp->pc,rp->outcode,(void*)rp->target,
858 (unsigned long long)rp->mcode,rp->type,rp->flags,rp->regalloccount);
860 for (j=0; j<rp->regalloccount; ++j)
861 printf("%c%1c%01x:%02d",
862 (rp->regalloc[j].next) ? '^' : ' ',
863 TYPECHAR(rp->regalloc[j].type),
864 rp->regalloc[j].flags,
865 rp->regalloc[j].index);
867 printf("]\n method: ");
868 method_print(rp->code->m);
874 /* replace_show_replacement_points *********************************************
876 Print replacement point info.
879 code.............codeinfo whose replacement points should be printed.
881 *******************************************************************************/
884 void replace_show_replacement_points(codeinfo *code)
890 printf("(codeinfo *)NULL\n");
894 printf("\treplacement points: %d\n",code->rplpointcount);
895 printf("\tglobal allocations: %d = [",code->globalcount);
897 for (i=0; i<code->globalcount; ++i)
898 printf("%c%1c%01x:%02d",
899 (code->regalloc[i].next) ? '^' : ' ',
900 TYPECHAR(code->regalloc[i].type),
901 code->regalloc[i].flags,code->regalloc[i].index);
905 printf("\ttotal allocations : %d\n",code->regalloccount);
906 printf("\tsaved int regs : %d\n",code->savedintcount);
907 printf("\tsaved flt regs : %d\n",code->savedfltcount);
908 printf("\tmemuse : %d\n",code->memuse);
912 for (i=0; i<code->rplpointcount; ++i) {
913 rp = code->rplpoints + i;
915 assert(rp->code == code);
918 replace_replacement_point_println(rp);
923 /* replace_executionstate_println **********************************************
925 Print execution state
928 es...............the execution state to print
929 code.............the codeinfo for which this execution state is meant
932 *******************************************************************************/
935 void replace_executionstate_println(executionstate *es,codeinfo *code)
939 #ifdef HAS_4BYTE_STACKSLOT
946 printf("(executionstate *)NULL\n");
950 printf("executionstate %p:\n",(void*)es);
951 printf("\tpc = %p\n",(void*)es->pc);
952 printf("\tsp = %p\n",(void*)es->sp);
953 printf("\tpv = %p\n",(void*)es->pv);
954 for (i=0; i<INT_REG_CNT; ++i) {
955 printf("\t%-3s = %016llx\n",regs[i],(unsigned long long)es->intregs[i]);
957 for (i=0; i<FLT_REG_CNT; ++i) {
958 printf("\tfltregs[%2d] = %016llx\n",i,(unsigned long long)es->fltregs[i]);
961 #ifdef HAS_4BYTE_STACKSLOT
968 slots = code_get_stack_frame_size(code);
972 printf("\tstack slots at sp:\n");
973 for (i=0; i<slots; ++i) {
974 #ifdef HAS_4BYTE_STACKSLOT
975 printf("\t\t%08lx\n",(unsigned long)*sp++);
977 printf("\t\t%016llx\n",(unsigned long long)*sp++);
985 /* replace_sourcestate_println *************************************************
990 ss...............the source state to print
992 *******************************************************************************/
995 void replace_sourcestate_println(sourcestate *ss)
1002 printf("(sourcestate *)NULL\n");
1006 printf("sourcestate %p: stackbase=%p\n",(void*)ss,(void*)ss->stackbase);
1008 printf("\tlocals (%d):\n",ss->javalocalcount);
1009 for (i=0; i<ss->javalocalcount; ++i) {
1010 for (t=0; t<5; ++t) {
1011 if (ss->javalocals[i*5+t] != 0x00dead0000dead00ULL) {
1012 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
1013 printf("%016llx\n",(unsigned long long) ss->javalocals[i*5+t]);
1020 printf("\tstack (depth %d):\n",ss->javastackdepth);
1021 for (i=0; i<ss->javastackdepth; ++i) {
1022 printf("\tstack[%2d] = ",i);
1023 printf("%016llx\n",(unsigned long long) ss->javastack[i]);
1028 printf("\tsaved int registers (%d):\n",INT_SAV_CNT);
1030 for (i=0; i<INT_SAV_CNT; ++i) {
1031 while (nregdescint[--reg] != REG_SAV)
1033 if (ss->savedintregs[i] != 0x00dead0000dead00ULL) {
1034 printf("\t%-3s = ",regs[reg]);
1035 printf("%016llx\n",(unsigned long long) ss->savedintregs[i]);
1041 printf("\tsaved float registers (%d):\n",FLT_SAV_CNT);
1042 for (i=0; i<FLT_SAV_CNT; ++i) {
1043 if (ss->savedfltregs[i] != 0x00dead0000dead00ULL) {
1044 printf("\tsavedfltreg[%2d] = ",i);
1045 printf("%016llx\n",(unsigned long long) ss->savedfltregs[i]);
1051 printf("\tsynchronization slots (%d):\n",ss->syncslotcount);
1052 for (i=0; i<ss->syncslotcount; ++i) {
1053 printf("\tslot[%2d] = ",i);
1054 #ifdef HAS_4BYTE_STACKSLOT
1055 printf("%08lx\n",(unsigned long) ss->syncslots[i]);
1057 printf("%016llx\n",(unsigned long long) ss->syncslots[i]);
1066 * These are local overrides for various environment variables in Emacs.
1067 * Please do not remove this and leave it at the end of the file, where
1068 * Emacs will automagically detect them.
1069 * ---------------------------------------------------------------------
1072 * indent-tabs-mode: t
1076 * vim:noexpandtab:sw=4:ts=4: