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 */
123 for (bptr = jd->new_basicblocks; bptr; bptr = bptr->next) {
124 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
127 /* there will be a replacement point at the start of this block */
130 alloccount += bptr->indepth;
133 /* if no points were found, there's nothing to do */
138 /* count global register allocations */
142 for (i=0; i<m->maxlocals; ++i) {
144 for (t=0; t<5; ++t) {
145 #if defined(ENABLE_INTRP)
148 if (rd->locals[i][t].type == t) {
152 #if defined(ENABLE_INTRP)
157 globalcount++; /* dummy rplalloc */
160 alloccount += globalcount;
162 /* allocate replacement point array and allocation array */
164 rplpoints = MNEW(rplpoint,count);
165 regalloc = MNEW(rplalloc,alloccount);
168 /* store global register allocations */
170 for (i=0; i<m->maxlocals; ++i) {
172 for (t=0; t<5; ++t) {
173 #if defined(ENABLE_INTRP)
176 if (rd->locals[i][t].type == t) {
177 ra->flags = rd->locals[i][t].flags & (INMEMORY);
178 ra->index = rd->locals[i][t].regoff;
180 ra->next = (indexused) ? 0 : 1;
184 #if defined(ENABLE_INTRP)
198 /* initialize replacement point structs */
202 for (bptr = jd->new_basicblocks; bptr; bptr = bptr->next) {
203 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
206 /* there will be a replacement point at the start of this block */
208 rp->pc = NULL; /* set by codegen */
209 rp->outcode = NULL; /* set by codegen */
214 rp->type = bptr->type;
216 /* store local allocation info */
218 for (sp = bptr->instack; sp; sp = sp->prev) {
219 ra->flags = sp->flags & (INMEMORY);
220 ra->index = sp->regoff;
226 rp->regalloccount = ra - rp->regalloc;
231 /* store the data in the codeinfo */
233 code->rplpoints = rplpoints;
234 code->rplpointcount = count;
235 code->regalloc = regalloc;
236 code->regalloccount = alloccount;
237 code->globalcount = globalcount;
238 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
239 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
240 code->memuse = rd->memuse;
242 /* everything alright */
247 /* replace_free_replacement_points *********************************************
249 Free memory used by replacement points.
252 code.............codeinfo whose replacement points should be freed.
254 *******************************************************************************/
256 void replace_free_replacement_points(codeinfo *code)
261 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
264 MFREE(code->regalloc,rplalloc,code->regalloccount);
266 code->rplpoints = NULL;
267 code->rplpointcount = 0;
268 code->regalloc = NULL;
269 code->regalloccount = 0;
270 code->globalcount = 0;
273 /* replace_activate_replacement_point ******************************************
275 Activate a replacement point. When this function returns, the
276 replacement point is "armed", that is each thread reaching this point
277 will be replace to `target`.
280 rp...............replacement point to activate
281 target...........target of replacement
283 *******************************************************************************/
285 void replace_activate_replacement_point(rplpoint *rp,rplpoint *target)
287 assert(rp->target == NULL);
290 printf("activate replacement point: ");
291 replace_replacement_point_println(rp);
297 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
298 md_patch_replacement_point(rp);
302 /* replace_deactivate_replacement_point ****************************************
304 Deactivate a replacement point. When this function returns, the
305 replacement point is "un-armed", that is a each thread reaching this point
306 will just continue normally.
309 rp...............replacement point to deactivate
311 *******************************************************************************/
313 void replace_deactivate_replacement_point(rplpoint *rp)
318 printf("deactivate replacement point: ");
319 replace_replacement_point_println(rp);
325 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
326 md_patch_replacement_point(rp);
330 /* replace_read_executionstate *************************************************
332 Read the given executions state and translate it to a source state.
335 rp...............replacement point at which `es` was taken
336 es...............execution state
337 ss...............where to put the source state
340 *ss..............the source state derived from the execution state
342 *******************************************************************************/
344 inline static void replace_read_value(executionstate *es,
345 #ifdef HAS_4BYTE_STACKSLOT
353 if (ra->flags & INMEMORY) {
354 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
355 #ifdef HAS_4BYTE_STACKSLOT
356 if (IS_2_WORD_TYPE(ra->type)) {
357 *javaval = *(u8*)(sp + ra->index);
361 *javaval = sp[ra->index];
362 #ifdef HAS_4BYTE_STACKSLOT
367 /* allocated register */
368 if (IS_FLT_DBL_TYPE(ra->type)) {
369 *javaval = es->fltregs[ra->index];
372 *javaval = es->intregs[ra->index];
377 inline static void replace_write_value(executionstate *es,
378 #ifdef HAS_4BYTE_STACKSLOT
386 if (ra->flags & INMEMORY) {
387 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
388 #ifdef HAS_4BYTE_STACKSLOT
389 if (IS_2_WORD_TYPE(ra->type)) {
390 *(u8*)(sp + ra->index) = *javaval;
394 sp[ra->index] = *javaval;
395 #ifdef HAS_4BYTE_STACKSLOT
400 /* allocated register */
401 if (IS_FLT_DBL_TYPE(ra->type)) {
402 es->fltregs[ra->index] = *javaval;
405 es->intregs[ra->index] = *javaval;
410 static void replace_read_executionstate(rplpoint *rp,executionstate *es,
422 #ifdef HAS_4BYTE_STACKSLOT
433 topslot = TOP_IS_NORMAL;
437 #ifdef HAS_4BYTE_STACKSLOT
443 /* on some architectures the returnAddress is passed on the stack by JSR */
445 #if defined(__I386__) || defined(__X86_64__)
446 if (rp->type == BBTYPE_SBR) {
448 topslot = TOP_IS_ON_STACK;
452 /* in some cases the top stack slot is passed in REG_ITMP1 */
454 if ( (rp->type == BBTYPE_EXH)
455 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)
456 || (rp->type == BBTYPE_SBR)
460 topslot = TOP_IS_IN_ITMP1;
463 /* calculate base stack pointer */
465 basesp = sp + code_get_stack_frame_size(code);
467 ss->stackbase = (u1*) basesp;
469 /* read local variables */
471 count = m->maxlocals;
472 ss->javalocalcount = count;
473 ss->javalocals = DMNEW(u8,count * 5);
476 /* mark values as undefined */
477 for (i=0; i<count*5; ++i)
478 ss->javalocals[i] = (u8) 0x00dead0000dead00ULL;
480 /* some entries in the intregs array are not meaningful */
481 /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
482 es->intregs[REG_SP ] = (u8) 0x11dead1111dead11ULL;
484 es->intregs[REG_PV ] = (u8) 0x11dead1111dead11ULL;
491 for (allocs = code->globalcount; allocs--; ra++) {
496 continue; /* dummy rplalloc */
498 replace_read_value(es,sp,ra,ss->javalocals + (5*i+t));
501 /* read stack slots */
503 count = rp->regalloccount;
504 ss->javastackdepth = count;
505 ss->javastack = DMNEW(u8,count);
508 /* mark values as undefined */
509 for (i=0; i<count; ++i)
510 ss->javastack[i] = (u8) 0x00dead0000dead00ULL;
516 /* the first stack slot is special in SBR and EXH blocks */
518 if (topslot == TOP_IS_ON_STACK) {
521 ss->javastack[i] = sp[-1];
526 else if (topslot == TOP_IS_IN_ITMP1) {
529 ss->javastack[i] = es->intregs[REG_ITMP1];
535 /* read remaining stack slots */
537 for (; count--; ra++, i++) {
540 replace_read_value(es,sp,ra,ss->javastack + i);
543 /* read unused callee saved int regs */
546 for (i=0; count > code->savedintcount; ++i) {
547 assert(i < INT_REG_CNT);
548 if (nregdescint[i] == REG_SAV)
549 ss->savedintregs[--count] = es->intregs[i];
552 /* read saved int regs */
554 for (i=0; i<code->savedintcount; ++i) {
555 ss->savedintregs[i] = *--basesp;
558 /* read unused callee saved flt regs */
561 for (i=0; count > code->savedfltcount; ++i) {
562 assert(i < FLT_REG_CNT);
563 if (nregdescfloat[i] == REG_SAV)
564 ss->savedfltregs[--count] = es->fltregs[i];
567 /* read saved flt regs */
569 for (i=0; i<code->savedfltcount; ++i) {
570 #ifdef HAS_4BYTE_STACKSLOT
575 ss->savedfltregs[i] = *(u8*)basesp;
578 /* read slots used for synchronization */
580 count = code_get_sync_slot_count(code);
581 ss->syncslotcount = count;
582 ss->syncslots = DMNEW(u8,count);
583 for (i=0; i<count; ++i) {
584 ss->syncslots[i] = sp[code->memuse + i];
588 /* replace_write_executionstate ************************************************
590 Translate the given source state into an execution state.
593 rp...............replacement point for which execution state should be
595 es...............where to put the execution state
596 ss...............the given source state
599 *es..............the execution state derived from the source state
601 *******************************************************************************/
603 static void replace_write_executionstate(rplpoint *rp,executionstate *es,
615 #ifdef HAS_4BYTE_STACKSLOT
626 topslot = TOP_IS_NORMAL;
628 /* calculate stack pointer */
630 #ifdef HAS_4BYTE_STACKSLOT
631 basesp = (u4*) ss->stackbase;
633 basesp = (u8*) ss->stackbase;
636 sp = basesp - code_get_stack_frame_size(code);
638 /* on some architectures the returnAddress is passed on the stack by JSR */
640 #if defined(__I386__) || defined(__X86_64__)
641 if (rp->type == BBTYPE_SBR) {
642 topslot = TOP_IS_ON_STACK;
646 /* in some cases the top stack slot is passed in REG_ITMP1 */
648 if ( (rp->type == BBTYPE_EXH)
649 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)
650 || (rp->type == BBTYPE_SBR)
654 topslot = TOP_IS_IN_ITMP1;
657 /* in debug mode, invalidate stack frame first */
660 for (i=0; i<(basesp - sp); ++i) {
665 /* write local variables */
667 count = m->maxlocals;
672 for (allocs = code->globalcount; allocs--; ra++) {
676 assert(i >= 0 && i < m->maxlocals);
680 continue; /* dummy rplalloc */
682 replace_write_value(es,sp,ra,ss->javalocals + (5*i+t));
685 /* write stack slots */
687 count = rp->regalloccount;
692 /* the first stack slot is special in SBR and EXH blocks */
694 if (topslot == TOP_IS_ON_STACK) {
697 sp[-1] = ss->javastack[i];
702 else if (topslot == TOP_IS_IN_ITMP1) {
705 es->intregs[REG_ITMP1] = ss->javastack[i];
711 /* write remaining stack slots */
713 for (; count--; ra++, i++) {
716 replace_write_value(es,sp,ra,ss->javastack + i);
719 /* write unused callee saved int regs */
722 for (i=0; count > code->savedintcount; ++i) {
723 assert(i < INT_REG_CNT);
724 if (nregdescint[i] == REG_SAV)
725 es->intregs[i] = ss->savedintregs[--count];
728 /* write saved int regs */
730 for (i=0; i<code->savedintcount; ++i) {
731 *--basesp = ss->savedintregs[i];
734 /* write unused callee saved flt regs */
737 for (i=0; count > code->savedfltcount; ++i) {
738 assert(i < FLT_REG_CNT);
739 if (nregdescfloat[i] == REG_SAV)
740 es->fltregs[i] = ss->savedfltregs[--count];
743 /* write saved flt regs */
745 for (i=0; i<code->savedfltcount; ++i) {
746 #ifdef HAS_4BYTE_STACKSLOT
751 *(u8*)basesp = ss->savedfltregs[i];
754 /* write slots used for synchronization */
756 count = code_get_sync_slot_count(code);
757 assert(count == ss->syncslotcount);
758 for (i=0; i<count; ++i) {
759 sp[code->memuse + i] = ss->syncslots[i];
767 /* replace_me ******************************************************************
769 This function is called by asm_replacement_out when a thread reaches
770 a replacement point. `replace_me` must map the execution state to the
771 target replacement point and let execution continue there.
773 This function never returns!
776 rp...............replacement point that has been reached
777 es...............execution state read by asm_replacement_out
779 *******************************************************************************/
781 void replace_me(rplpoint *rp,executionstate *es)
787 /* mark start of dump memory area */
789 dumpsize = dump_size();
791 /* fetch the target of the replacement */
795 /* XXX DEBUG turn off self-replacement */
797 replace_deactivate_replacement_point(rp);
800 printf("replace_me(%p,%p)\n",(void*)rp,(void*)es);
802 replace_replacement_point_println(rp);
803 replace_executionstate_println(es,rp->code);
806 /* read execution state of old code */
808 replace_read_executionstate(rp,es,&ss);
811 replace_sourcestate_println(&ss);
814 /* write execution state of new code */
816 replace_write_executionstate(target,es,&ss);
819 replace_executionstate_println(es,target->code);
822 /* release dump area */
824 dump_release(dumpsize);
828 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
829 asm_replacement_in(es);
834 /* replace_replacement_point_println *******************************************
836 Print replacement point info.
839 rp...............the replacement point to print
841 *******************************************************************************/
844 static const char *type_char = "IJFDA";
846 #define TYPECHAR(t) (((t) >= 0 && (t) <= 4) ? type_char[t] : '?')
848 void replace_replacement_point_println(rplpoint *rp)
853 printf("(rplpoint *)NULL\n");
857 printf("rplpoint %p pc:%p out:%p target:%p mcode:%016llx type:%01d flags:%01x ra:%d = [",
858 (void*)rp,rp->pc,rp->outcode,(void*)rp->target,
859 (unsigned long long)rp->mcode,rp->type,rp->flags,rp->regalloccount);
861 for (j=0; j<rp->regalloccount; ++j)
862 printf("%c%1c%01x:%02d",
863 (rp->regalloc[j].next) ? '^' : ' ',
864 TYPECHAR(rp->regalloc[j].type),
865 rp->regalloc[j].flags,
866 rp->regalloc[j].index);
868 printf("]\n method: ");
869 method_print(rp->code->m);
875 /* replace_show_replacement_points *********************************************
877 Print replacement point info.
880 code.............codeinfo whose replacement points should be printed.
882 *******************************************************************************/
885 void replace_show_replacement_points(codeinfo *code)
891 printf("(codeinfo *)NULL\n");
895 printf("\treplacement points: %d\n",code->rplpointcount);
896 printf("\tglobal allocations: %d = [",code->globalcount);
898 for (i=0; i<code->globalcount; ++i)
899 printf("%c%1c%01x:%02d",
900 (code->regalloc[i].next) ? '^' : ' ',
901 TYPECHAR(code->regalloc[i].type),
902 code->regalloc[i].flags,code->regalloc[i].index);
906 printf("\ttotal allocations : %d\n",code->regalloccount);
907 printf("\tsaved int regs : %d\n",code->savedintcount);
908 printf("\tsaved flt regs : %d\n",code->savedfltcount);
909 printf("\tmemuse : %d\n",code->memuse);
913 for (i=0; i<code->rplpointcount; ++i) {
914 rp = code->rplpoints + i;
916 assert(rp->code == code);
919 replace_replacement_point_println(rp);
924 /* replace_executionstate_println **********************************************
926 Print execution state
929 es...............the execution state to print
930 code.............the codeinfo for which this execution state is meant
933 *******************************************************************************/
936 void replace_executionstate_println(executionstate *es,codeinfo *code)
940 #ifdef HAS_4BYTE_STACKSLOT
947 printf("(executionstate *)NULL\n");
951 printf("executionstate %p:\n",(void*)es);
952 printf("\tpc = %p\n",(void*)es->pc);
953 printf("\tsp = %p\n",(void*)es->sp);
954 printf("\tpv = %p\n",(void*)es->pv);
955 #if defined(ENABLE_DISASSEMBLER)
956 for (i=0; i<INT_REG_CNT; ++i) {
957 printf("\t%-3s = %016llx\n",regs[i],(unsigned long long)es->intregs[i]);
959 for (i=0; i<FLT_REG_CNT; ++i) {
960 printf("\tfltregs[%2d] = %016llx\n",i,(unsigned long long)es->fltregs[i]);
964 #ifdef HAS_4BYTE_STACKSLOT
971 slots = code_get_stack_frame_size(code);
975 printf("\tstack slots at sp:\n");
976 for (i=0; i<slots; ++i) {
977 #ifdef HAS_4BYTE_STACKSLOT
978 printf("\t\t%08lx\n",(unsigned long)*sp++);
980 printf("\t\t%016llx\n",(unsigned long long)*sp++);
988 /* replace_sourcestate_println *************************************************
993 ss...............the source state to print
995 *******************************************************************************/
998 void replace_sourcestate_println(sourcestate *ss)
1005 printf("(sourcestate *)NULL\n");
1009 printf("sourcestate %p: stackbase=%p\n",(void*)ss,(void*)ss->stackbase);
1011 printf("\tlocals (%d):\n",ss->javalocalcount);
1012 for (i=0; i<ss->javalocalcount; ++i) {
1013 for (t=0; t<5; ++t) {
1014 if (ss->javalocals[i*5+t] != 0x00dead0000dead00ULL) {
1015 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
1016 printf("%016llx\n",(unsigned long long) ss->javalocals[i*5+t]);
1023 printf("\tstack (depth %d):\n",ss->javastackdepth);
1024 for (i=0; i<ss->javastackdepth; ++i) {
1025 printf("\tstack[%2d] = ",i);
1026 printf("%016llx\n",(unsigned long long) ss->javastack[i]);
1031 printf("\tsaved int registers (%d):\n",INT_SAV_CNT);
1033 for (i=0; i<INT_SAV_CNT; ++i) {
1034 while (nregdescint[--reg] != REG_SAV)
1036 if (ss->savedintregs[i] != 0x00dead0000dead00ULL) {
1037 #if defined(ENABLE_DISASSEMBLER)
1038 printf("\t%-3s = ",regs[reg]);
1040 printf("%016llx\n",(unsigned long long) ss->savedintregs[i]);
1046 printf("\tsaved float registers (%d):\n",FLT_SAV_CNT);
1047 for (i=0; i<FLT_SAV_CNT; ++i) {
1048 if (ss->savedfltregs[i] != 0x00dead0000dead00ULL) {
1049 printf("\tsavedfltreg[%2d] = ",i);
1050 printf("%016llx\n",(unsigned long long) ss->savedfltregs[i]);
1056 printf("\tsynchronization slots (%d):\n",ss->syncslotcount);
1057 for (i=0; i<ss->syncslotcount; ++i) {
1058 printf("\tslot[%2d] = ",i);
1059 #ifdef HAS_4BYTE_STACKSLOT
1060 printf("%08lx\n",(unsigned long) ss->syncslots[i]);
1062 printf("%016llx\n",(unsigned long long) ss->syncslots[i]);
1071 * These are local overrides for various environment variables in Emacs.
1072 * Please do not remove this and leave it at the end of the file, where
1073 * Emacs will automagically detect them.
1074 * ---------------------------------------------------------------------
1077 * indent-tabs-mode: t
1081 * vim:noexpandtab:sw=4:ts=4: