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;
240 /* everything alright */
245 /* replace_free_replacement_points *********************************************
247 Free memory used by replacement points.
250 code.............codeinfo whose replacement points should be freed.
252 *******************************************************************************/
254 void replace_free_replacement_points(codeinfo *code)
259 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
262 MFREE(code->regalloc,rplalloc,code->regalloccount);
264 code->rplpoints = NULL;
265 code->rplpointcount = 0;
266 code->regalloc = NULL;
267 code->regalloccount = 0;
268 code->globalcount = 0;
271 /* replace_activate_replacement_point ******************************************
273 Activate a replacement point. When this function returns, the
274 replacement point is "armed", that is each thread reaching this point
275 will be replace to `target`.
278 rp...............replacement point to activate
279 target...........target of replacement
281 *******************************************************************************/
283 void replace_activate_replacement_point(rplpoint *rp,rplpoint *target)
285 assert(rp->target == NULL);
288 printf("activate replacement point: ");
289 replace_replacement_point_println(rp);
295 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
296 md_patch_replacement_point(rp);
300 /* replace_deactivate_replacement_point ****************************************
302 Deactivate a replacement point. When this function returns, the
303 replacement point is "un-armed", that is a each thread reaching this point
304 will just continue normally.
307 rp...............replacement point to deactivate
309 *******************************************************************************/
311 void replace_deactivate_replacement_point(rplpoint *rp)
316 printf("deactivate replacement point: ");
317 replace_replacement_point_println(rp);
323 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
324 md_patch_replacement_point(rp);
328 /* replace_read_executionstate *************************************************
330 Read the given executions state and translate it to a source state.
333 rp...............replacement point at which `es` was taken
334 es...............execution state
335 ss...............where to put the source state
338 *ss..............the source state derived from the execution state
340 *******************************************************************************/
342 inline static void replace_read_value(executionstate *es,
343 #ifdef HAS_4BYTE_STACKSLOT
351 if (ra->flags & INMEMORY) {
352 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
353 #ifdef HAS_4BYTE_STACKSLOT
354 if (IS_2_WORD_TYPE(ra->type)) {
355 *javaval = *(u8*)(sp + ra->index);
359 *javaval = sp[ra->index];
360 #ifdef HAS_4BYTE_STACKSLOT
365 /* allocated register */
366 if (IS_FLT_DBL_TYPE(ra->type)) {
367 *javaval = es->fltregs[ra->index];
370 *javaval = es->intregs[ra->index];
375 inline static void replace_write_value(executionstate *es,
376 #ifdef HAS_4BYTE_STACKSLOT
384 if (ra->flags & INMEMORY) {
385 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
386 #ifdef HAS_4BYTE_STACKSLOT
387 if (IS_2_WORD_TYPE(ra->type)) {
388 *(u8*)(sp + ra->index) = *javaval;
392 sp[ra->index] = *javaval;
393 #ifdef HAS_4BYTE_STACKSLOT
398 /* allocated register */
399 if (IS_FLT_DBL_TYPE(ra->type)) {
400 es->fltregs[ra->index] = *javaval;
403 es->intregs[ra->index] = *javaval;
408 static void replace_read_executionstate(rplpoint *rp,executionstate *es,
420 #ifdef HAS_4BYTE_STACKSLOT
431 topslot = TOP_IS_NORMAL;
435 #ifdef HAS_4BYTE_STACKSLOT
441 /* on some architectures the returnAddress is passed on the stack by JSR */
443 #if defined(__I386__) || defined(__X86_64__)
444 if (rp->type == BBTYPE_SBR) {
446 topslot = TOP_IS_ON_STACK;
450 /* in some cases the top stack slot is passed in REG_ITMP1 */
452 if ( (rp->type == BBTYPE_EXH)
453 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)
454 || (rp->type == BBTYPE_SBR)
458 topslot = TOP_IS_IN_ITMP1;
461 /* calculate base stack pointer */
463 basesp = sp + code_get_stack_frame_size(code);
465 ss->stackbase = (u1*) basesp;
467 /* read local variables */
469 count = m->maxlocals;
470 ss->javalocalcount = count;
471 ss->javalocals = DMNEW(u8,count * 5);
474 /* mark values as undefined */
475 for (i=0; i<count*5; ++i)
476 ss->javalocals[i] = (u8) 0x00dead0000dead00ULL;
478 /* some entries in the intregs array are not meaningful */
479 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
480 es->intregs[REG_SP ] = (u8) 0x11dead1111dead11ULL;
482 es->intregs[REG_PV ] = (u8) 0x11dead1111dead11ULL;
489 for (allocs = code->globalcount; allocs--; ra++) {
494 continue; /* dummy rplalloc */
496 replace_read_value(es,sp,ra,ss->javalocals + (5*i+t));
499 /* read stack slots */
501 count = rp->regalloccount;
502 ss->javastackdepth = count;
503 ss->javastack = DMNEW(u8,count);
506 /* mark values as undefined */
507 for (i=0; i<count; ++i)
508 ss->javastack[i] = (u8) 0x00dead0000dead00ULL;
514 /* the first stack slot is special in SBR and EXH blocks */
516 if (topslot == TOP_IS_ON_STACK) {
519 ss->javastack[i] = sp[-1];
524 else if (topslot == TOP_IS_IN_ITMP1) {
527 ss->javastack[i] = es->intregs[REG_ITMP1];
533 /* read remaining stack slots */
535 for (; count--; ra++, i++) {
538 replace_read_value(es,sp,ra,ss->javastack + i);
541 /* read unused callee saved int regs */
544 for (i=0; count > code->savedintcount; ++i) {
545 assert(i < INT_REG_CNT);
546 if (nregdescint[i] == REG_SAV)
547 ss->savedintregs[--count] = es->intregs[i];
550 /* read saved int regs */
552 for (i=0; i<code->savedintcount; ++i) {
553 ss->savedintregs[i] = *--basesp;
556 /* read unused callee saved flt regs */
559 for (i=0; count > code->savedfltcount; ++i) {
560 assert(i < FLT_REG_CNT);
561 if (nregdescfloat[i] == REG_SAV)
562 ss->savedfltregs[--count] = es->fltregs[i];
565 /* read saved flt regs */
567 for (i=0; i<code->savedfltcount; ++i) {
568 #ifdef HAS_4BYTE_STACKSLOT
573 ss->savedfltregs[i] = *(u8*)basesp;
576 /* read slots used for synchronization */
578 count = code_get_sync_slot_count(code);
579 ss->syncslotcount = count;
580 ss->syncslots = DMNEW(u8,count);
581 for (i=0; i<count; ++i) {
582 ss->syncslots[i] = sp[code->memuse + i];
586 /* replace_write_executionstate ************************************************
588 Translate the given source state into an execution state.
591 rp...............replacement point for which execution state should be
593 es...............where to put the execution state
594 ss...............the given source state
597 *es..............the execution state derived from the source state
599 *******************************************************************************/
601 static void replace_write_executionstate(rplpoint *rp,executionstate *es,
613 #ifdef HAS_4BYTE_STACKSLOT
624 topslot = TOP_IS_NORMAL;
626 /* calculate stack pointer */
628 #ifdef HAS_4BYTE_STACKSLOT
629 basesp = (u4*) ss->stackbase;
631 basesp = (u8*) ss->stackbase;
634 sp = basesp - code_get_stack_frame_size(code);
636 /* on some architectures the returnAddress is passed on the stack by JSR */
638 #if defined(__I386__) || defined(__X86_64__)
639 if (rp->type == BBTYPE_SBR) {
640 topslot = TOP_IS_ON_STACK;
644 /* in some cases the top stack slot is passed in REG_ITMP1 */
646 if ( (rp->type == BBTYPE_EXH)
647 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)
648 || (rp->type == BBTYPE_SBR)
652 topslot = TOP_IS_IN_ITMP1;
655 /* in debug mode, invalidate stack frame first */
658 for (i=0; i<(basesp - sp); ++i) {
663 /* write local variables */
665 count = m->maxlocals;
670 for (allocs = code->globalcount; allocs--; ra++) {
674 assert(i >= 0 && i < m->maxlocals);
678 continue; /* dummy rplalloc */
680 replace_write_value(es,sp,ra,ss->javalocals + (5*i+t));
683 /* write stack slots */
685 count = rp->regalloccount;
690 /* the first stack slot is special in SBR and EXH blocks */
692 if (topslot == TOP_IS_ON_STACK) {
695 sp[-1] = ss->javastack[i];
700 else if (topslot == TOP_IS_IN_ITMP1) {
703 es->intregs[REG_ITMP1] = ss->javastack[i];
709 /* write remaining stack slots */
711 for (; count--; ra++, i++) {
714 replace_write_value(es,sp,ra,ss->javastack + i);
717 /* write unused callee saved int regs */
720 for (i=0; count > code->savedintcount; ++i) {
721 assert(i < INT_REG_CNT);
722 if (nregdescint[i] == REG_SAV)
723 es->intregs[i] = ss->savedintregs[--count];
726 /* write saved int regs */
728 for (i=0; i<code->savedintcount; ++i) {
729 *--basesp = ss->savedintregs[i];
732 /* write unused callee saved flt regs */
735 for (i=0; count > code->savedfltcount; ++i) {
736 assert(i < FLT_REG_CNT);
737 if (nregdescfloat[i] == REG_SAV)
738 es->fltregs[i] = ss->savedfltregs[--count];
741 /* write saved flt regs */
743 for (i=0; i<code->savedfltcount; ++i) {
744 #ifdef HAS_4BYTE_STACKSLOT
749 *(u8*)basesp = ss->savedfltregs[i];
752 /* write slots used for synchronization */
754 count = code_get_sync_slot_count(code);
755 assert(count == ss->syncslotcount);
756 for (i=0; i<count; ++i) {
757 sp[code->memuse + i] = ss->syncslots[i];
765 /* replace_me ******************************************************************
767 This function is called by asm_replacement_out when a thread reaches
768 a replacement point. `replace_me` must map the execution state to the
769 target replacement point and let execution continue there.
771 This function never returns!
774 rp...............replacement point that has been reached
775 es...............execution state read by asm_replacement_out
777 *******************************************************************************/
779 void replace_me(rplpoint *rp,executionstate *es)
785 /* mark start of dump memory area */
787 dumpsize = dump_size();
789 /* fetch the target of the replacement */
793 /* XXX DEBUG turn off self-replacement */
795 replace_deactivate_replacement_point(rp);
798 printf("replace_me(%p,%p)\n",(void*)rp,(void*)es);
800 replace_replacement_point_println(rp);
801 replace_executionstate_println(es,rp->code);
804 /* read execution state of old code */
806 replace_read_executionstate(rp,es,&ss);
809 replace_sourcestate_println(&ss);
812 /* write execution state of new code */
814 replace_write_executionstate(target,es,&ss);
817 replace_executionstate_println(es,target->code);
820 /* release dump area */
822 dump_release(dumpsize);
826 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
827 asm_replacement_in(es);
832 /* replace_replacement_point_println *******************************************
834 Print replacement point info.
837 rp...............the replacement point to print
839 *******************************************************************************/
842 static const char *type_char = "IJFDA";
844 #define TYPECHAR(t) (((t) >= 0 && (t) <= 4) ? type_char[t] : '?')
846 void replace_replacement_point_println(rplpoint *rp)
851 printf("(rplpoint *)NULL\n");
855 printf("rplpoint %p pc:%p out:%p target:%p mcode:%016llx type:%01d flags:%01x ra:%d = [",
856 (void*)rp,rp->pc,rp->outcode,(void*)rp->target,
857 (unsigned long long)rp->mcode,rp->type,rp->flags,rp->regalloccount);
859 for (j=0; j<rp->regalloccount; ++j)
860 printf("%c%1c%01x:%02d",
861 (rp->regalloc[j].next) ? '^' : ' ',
862 TYPECHAR(rp->regalloc[j].type),
863 rp->regalloc[j].flags,
864 rp->regalloc[j].index);
866 printf("]\n method: ");
867 method_print(rp->code->m);
873 /* replace_show_replacement_points *********************************************
875 Print replacement point info.
878 code.............codeinfo whose replacement points should be printed.
880 *******************************************************************************/
883 void replace_show_replacement_points(codeinfo *code)
889 printf("(codeinfo *)NULL\n");
893 printf("\treplacement points: %d\n",code->rplpointcount);
894 printf("\tglobal allocations: %d = [",code->globalcount);
896 for (i=0; i<code->globalcount; ++i)
897 printf("%c%1c%01x:%02d",
898 (code->regalloc[i].next) ? '^' : ' ',
899 TYPECHAR(code->regalloc[i].type),
900 code->regalloc[i].flags,code->regalloc[i].index);
904 printf("\ttotal allocations : %d\n",code->regalloccount);
905 printf("\tsaved int regs : %d\n",code->savedintcount);
906 printf("\tsaved flt regs : %d\n",code->savedfltcount);
907 printf("\tmemuse : %d\n",code->memuse);
911 for (i=0; i<code->rplpointcount; ++i) {
912 rp = code->rplpoints + i;
914 assert(rp->code == code);
917 replace_replacement_point_println(rp);
922 /* replace_executionstate_println **********************************************
924 Print execution state
927 es...............the execution state to print
928 code.............the codeinfo for which this execution state is meant
931 *******************************************************************************/
934 void replace_executionstate_println(executionstate *es,codeinfo *code)
938 #ifdef HAS_4BYTE_STACKSLOT
945 printf("(executionstate *)NULL\n");
949 printf("executionstate %p:\n",(void*)es);
950 printf("\tpc = %p\n",(void*)es->pc);
951 printf("\tsp = %p\n",(void*)es->sp);
952 printf("\tpv = %p\n",(void*)es->pv);
953 #if defined(ENABLE_DISASSEMBLER)
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]);
962 #ifdef HAS_4BYTE_STACKSLOT
969 slots = code_get_stack_frame_size(code);
973 printf("\tstack slots at sp:\n");
974 for (i=0; i<slots; ++i) {
975 #ifdef HAS_4BYTE_STACKSLOT
976 printf("\t\t%08lx\n",(unsigned long)*sp++);
978 printf("\t\t%016llx\n",(unsigned long long)*sp++);
986 /* replace_sourcestate_println *************************************************
991 ss...............the source state to print
993 *******************************************************************************/
996 void replace_sourcestate_println(sourcestate *ss)
1003 printf("(sourcestate *)NULL\n");
1007 printf("sourcestate %p: stackbase=%p\n",(void*)ss,(void*)ss->stackbase);
1009 printf("\tlocals (%d):\n",ss->javalocalcount);
1010 for (i=0; i<ss->javalocalcount; ++i) {
1011 for (t=0; t<5; ++t) {
1012 if (ss->javalocals[i*5+t] != 0x00dead0000dead00ULL) {
1013 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
1014 printf("%016llx\n",(unsigned long long) ss->javalocals[i*5+t]);
1021 printf("\tstack (depth %d):\n",ss->javastackdepth);
1022 for (i=0; i<ss->javastackdepth; ++i) {
1023 printf("\tstack[%2d] = ",i);
1024 printf("%016llx\n",(unsigned long long) ss->javastack[i]);
1029 printf("\tsaved int registers (%d):\n",INT_SAV_CNT);
1031 for (i=0; i<INT_SAV_CNT; ++i) {
1032 while (nregdescint[--reg] != REG_SAV)
1034 if (ss->savedintregs[i] != 0x00dead0000dead00ULL) {
1035 #if defined(ENABLE_DISASSEMBLER)
1036 printf("\t%-3s = ",regs[reg]);
1038 printf("%016llx\n",(unsigned long long) ss->savedintregs[i]);
1044 printf("\tsaved float registers (%d):\n",FLT_SAV_CNT);
1045 for (i=0; i<FLT_SAV_CNT; ++i) {
1046 if (ss->savedfltregs[i] != 0x00dead0000dead00ULL) {
1047 printf("\tsavedfltreg[%2d] = ",i);
1048 printf("%016llx\n",(unsigned long long) ss->savedfltregs[i]);
1054 printf("\tsynchronization slots (%d):\n",ss->syncslotcount);
1055 for (i=0; i<ss->syncslotcount; ++i) {
1056 printf("\tslot[%2d] = ",i);
1057 #ifdef HAS_4BYTE_STACKSLOT
1058 printf("%08lx\n",(unsigned long) ss->syncslots[i]);
1060 printf("%016llx\n",(unsigned long long) ss->syncslots[i]);
1069 * These are local overrides for various environment variables in Emacs.
1070 * Please do not remove this and leave it at the end of the file, where
1071 * Emacs will automagically detect them.
1072 * ---------------------------------------------------------------------
1075 * indent-tabs-mode: t
1079 * vim:noexpandtab:sw=4:ts=4: