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(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(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 static void replace_read_executionstate(rplpoint *rp,executionstate *es,
345 #ifdef HAS_4BYTE_STACKSLOT
356 topslot = TOP_IS_NORMAL;
360 #ifdef HAS_4BYTE_STACKSLOT
366 /* on some architectures the returnAddress is passed on the stack by JSR */
368 #if defined(__I386__) || defined(__X86_64__)
369 if (rp->type == BBTYPE_SBR) {
371 topslot = TOP_IS_ON_STACK;
375 /* in some cases the top stack slot is passed in REG_ITMP1 */
377 if ( (rp->type == BBTYPE_EXH)
378 #if defined(__ALPHA__)
379 || (rp->type == BBTYPE_SBR)
383 topslot = TOP_IS_IN_ITMP1;
386 /* calculate base stack pointer */
388 basesp = sp + code_get_stack_frame_size(code);
390 ss->stackbase = (u1*) basesp;
392 /* read local variables */
394 count = m->maxlocals;
395 ss->javalocalcount = count;
396 ss->javalocals = DMNEW(u8,count * 5);
399 /* mark values as undefined */
400 for (i=0; i<count*5; ++i)
401 ss->javalocals[i] = (u8) 0x00dead0000dead00ULL;
403 /* some entries in the intregs array are not meaningful */
404 es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;
405 es->intregs[REG_SP ] = (u8) 0x11dead1111dead11ULL;
407 es->intregs[REG_PV ] = (u8) 0x11dead1111dead11ULL;
414 for (allocs = code->globalcount; allocs--; ra++) {
419 continue; /* dummy rplalloc */
421 #ifdef HAS_4BYTE_STACKSLOT
422 if (IS_2_WORD_TYPE(ra->type)) {
423 if (ra->flags & INMEMORY) {
424 ss->javalocals[i*5+t] = *(u8*)(sp + ra->index);
427 dolog("XXX split 2-word types in registers are not supported");
433 if (ra->flags & INMEMORY) {
434 ss->javalocals[i*5+t] = sp[ra->index];
437 ss->javalocals[i*5+t] = es->intregs[ra->index];
439 #ifdef HAS_4BYTE_STACKSLOT
444 /* read stack slots */
446 count = rp->regalloccount;
447 ss->javastackdepth = count;
448 ss->javastack = DMNEW(u8,count);
451 /* mark values as undefined */
452 for (i=0; i<count; ++i)
453 ss->javastack[i] = (u8) 0x00dead0000dead00ULL;
459 /* the first stack slot is special in SBR and EXH blocks */
461 if (topslot == TOP_IS_ON_STACK) {
464 ss->javastack[i] = sp[-1];
469 else if (topslot == TOP_IS_IN_ITMP1) {
472 ss->javastack[i] = es->intregs[REG_ITMP1];
478 /* read remaining stack slots */
480 for (; count--; ra++, i++) {
483 if (ra->flags & INMEMORY) {
484 ss->javastack[i] = sp[ra->index];
487 ss->javastack[i] = es->intregs[ra->index];
491 /* read unused callee saved int regs */
494 for (i=0; count > code->savedintcount; ++i) {
495 assert(i < INT_REG_CNT);
496 if (nregdescint[i] == REG_SAV)
497 ss->savedintregs[--count] = es->intregs[i];
500 /* read saved int regs */
502 for (i=0; i<code->savedintcount; ++i) {
503 ss->savedintregs[i] = *--basesp;
506 /* read unused callee saved flt regs */
509 for (i=0; count > code->savedfltcount; ++i) {
510 assert(i < FLT_REG_CNT);
511 if (nregdescfloat[i] == REG_SAV)
512 ss->savedfltregs[--count] = es->fltregs[i];
515 /* read saved flt regs */
517 for (i=0; i<code->savedfltcount; ++i) {
518 #ifdef HAS_4BYTE_STACKSLOT
523 ss->savedfltregs[i] = *(u8*)basesp;
526 /* read slots used for synchronization */
528 count = code_get_sync_slot_count(code);
529 ss->syncslotcount = count;
530 ss->syncslots = DMNEW(u8,count);
531 for (i=0; i<count; ++i) {
532 ss->syncslots[i] = sp[code->memuse + i];
536 /* replace_write_executionstate ************************************************
538 Translate the given source state into an execution state.
541 rp...............replacement point for which execution state should be
543 es...............where to put the execution state
544 ss...............the given source state
547 *es..............the execution state derived from the source state
549 *******************************************************************************/
551 static void replace_write_executionstate(rplpoint *rp,executionstate *es,
563 #ifdef HAS_4BYTE_STACKSLOT
575 /* calculate stack pointer */
577 #ifdef HAS_4BYTE_STACKSLOT
578 basesp = (u4*) ss->stackbase;
580 basesp = (u8*) ss->stackbase;
583 sp = basesp - code_get_stack_frame_size(code);
585 /* on some architectures the returnAddress is passed on the stack by JSR */
587 #if defined(__I386__) || defined(__X86_64__)
588 if (rp->type == BBTYPE_SBR) {
589 topslot = TOP_IS_ON_STACK;
593 /* in some cases the top stack slot is passed in REG_ITMP1 */
595 if ( (rp->type == BBTYPE_EXH)
596 #if defined(__ALPHA__)
597 || (rp->type == BBTYPE_SBR)
601 topslot = TOP_IS_IN_ITMP1;
604 /* in debug mode, invalidate stack frame first */
607 for (i=0; i<(basesp - sp); ++i) {
612 /* write local variables */
614 count = m->maxlocals;
619 for (allocs = code->globalcount; allocs--; ra++) {
623 assert(i >= 0 && i < m->maxlocals);
627 continue; /* dummy rplalloc */
629 #ifdef HAS_4BYTE_STACKSLOT
630 if (IS_2_WORD_TYPE(ra->type)) {
631 if (ra->flags & INMEMORY) {
632 *(u8*)(sp + ra->index) = ss->javalocals[i*5+t];
635 dolog("XXX split 2-word types in registers are not supported");
641 if (ra->flags & INMEMORY) {
642 sp[ra->index] = ss->javalocals[i*5+t];
645 es->intregs[ra->index] = ss->javalocals[i*5+t];
647 #ifdef HAS_4BYTE_STACKSLOT
652 /* write stack slots */
654 count = rp->regalloccount;
659 /* the first stack slot is special in SBR and EXH blocks */
661 if (topslot == TOP_IS_ON_STACK) {
664 sp[-1] = ss->javastack[i];
669 else if (topslot == TOP_IS_IN_ITMP1) {
672 es->intregs[REG_ITMP1] = ss->javastack[i];
678 /* write remaining stack slots */
680 for (; count--; ra++, i++) {
683 if (ra->flags & INMEMORY) {
684 sp[ra->index] = ss->javastack[i];
687 es->intregs[ra->index] = ss->javastack[i];
691 /* write unused callee saved int regs */
694 for (i=0; count > code->savedintcount; ++i) {
695 assert(i < INT_REG_CNT);
696 if (nregdescint[i] == REG_SAV)
697 es->intregs[i] = ss->savedintregs[--count];
700 /* write saved int regs */
702 for (i=0; i<code->savedintcount; ++i) {
703 *--basesp = ss->savedintregs[i];
706 /* write unused callee saved flt regs */
709 for (i=0; count > code->savedfltcount; ++i) {
710 assert(i < FLT_REG_CNT);
711 if (nregdescfloat[i] == REG_SAV)
712 es->fltregs[i] = ss->savedfltregs[--count];
715 /* write saved flt regs */
717 for (i=0; i<code->savedfltcount; ++i) {
718 #ifdef HAS_4BYTE_STACKSLOT
723 *(u8*)basesp = ss->savedfltregs[i];
726 /* write slots used for synchronization */
728 count = code_get_sync_slot_count(code);
729 assert(count == ss->syncslotcount);
730 for (i=0; i<count; ++i) {
731 sp[code->memuse + i] = ss->syncslots[i];
739 /* replace_me ******************************************************************
741 This function is called by asm_replacement_out when a thread reaches
742 a replacement point. `replace_me` must map the execution state to the
743 target replacement point and let execution continue there.
745 This function never returns!
748 rp...............replacement point that has been reached
749 es...............execution state read by asm_replacement_out
751 *******************************************************************************/
753 void replace_me(rplpoint *rp,executionstate *es)
759 /* mark start of dump memory area */
761 dumpsize = dump_size();
763 /* fetch the target of the replacement */
767 /* XXX DEBUG turn of self-replacement */
769 replace_deactivate_replacement_point(rp);
772 printf("replace_me(%p,%p)\n",(void*)rp,(void*)es);
774 replace_replacement_point_println(rp);
775 replace_executionstate_println(es,rp->code);
778 /* read execution state of old code */
780 replace_read_executionstate(rp,es,&ss);
783 replace_sourcestate_println(&ss);
786 /* write execution state of new code */
788 replace_write_executionstate(target,es,&ss);
791 replace_executionstate_println(es,target->code);
794 /* release dump area */
796 dump_release(dumpsize);
800 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__)) && defined(ENABLE_JIT)
801 asm_replacement_in(es);
806 /* replace_replacement_point_println *******************************************
808 Print replacement point info.
811 rp...............the replacement point to print
813 *******************************************************************************/
816 static const char *type_char = "IJFDA";
818 #define TYPECHAR(t) (((t) >= 0 && (t) <= 4) ? type_char[t] : '?')
820 void replace_replacement_point_println(rplpoint *rp)
825 printf("(rplpoint *)NULL\n");
829 printf("rplpoint %p pc:%p out:%p target:%p mcode:%016llx type:%01d flags:%01x ra:%d = [",
830 (void*)rp,rp->pc,rp->outcode,(void*)rp->target,
831 (unsigned long long)rp->mcode,rp->type,rp->flags,rp->regalloccount);
833 for (j=0; j<rp->regalloccount; ++j)
834 printf("%c%1c%01x:%02d",
835 (rp->regalloc[j].next) ? '^' : ' ',
836 TYPECHAR(rp->regalloc[j].type),
837 rp->regalloc[j].flags,
838 rp->regalloc[j].index);
840 printf("]\n method: ");
841 method_print(rp->code->m);
847 /* replace_show_replacement_points *********************************************
849 Print replacement point info.
852 code.............codeinfo whose replacement points should be printed.
854 *******************************************************************************/
857 void replace_show_replacement_points(codeinfo *code)
863 printf("(codeinfo *)NULL\n");
867 printf("\treplacement points: %d\n",code->rplpointcount);
868 printf("\tglobal allocations: %d = [",code->globalcount);
870 for (i=0; i<code->globalcount; ++i)
871 printf("%c%1c%01x:%02d",
872 (code->regalloc[i].next) ? '^' : ' ',
873 TYPECHAR(code->regalloc[i].type),
874 code->regalloc[i].flags,code->regalloc[i].index);
878 printf("\ttotal allocations : %d\n",code->regalloccount);
879 printf("\tsaved int regs : %d\n",code->savedintcount);
880 printf("\tsaved flt regs : %d\n",code->savedfltcount);
881 printf("\tmemuse : %d\n",code->memuse);
885 for (i=0; i<code->rplpointcount; ++i) {
886 rp = code->rplpoints + i;
888 assert(rp->code == code);
891 replace_replacement_point_println(rp);
896 /* replace_executionstate_println **********************************************
898 Print execution state
901 es...............the execution state to print
902 code.............the codeinfo for which this execution state is meant
905 *******************************************************************************/
908 void replace_executionstate_println(executionstate *es,codeinfo *code)
912 #ifdef HAS_4BYTE_STACKSLOT
919 printf("(executionstate *)NULL\n");
923 printf("executionstate %p:\n",(void*)es);
924 printf("\tpc = %p\n",(void*)es->pc);
925 printf("\tsp = %p\n",(void*)es->sp);
926 printf("\tpv = %p\n",(void*)es->pv);
927 for (i=0; i<INT_REG_CNT; ++i) {
928 printf("\t%-3s = %016llx\n",regs[i],(unsigned long long)es->intregs[i]);
930 for (i=0; i<FLT_REG_CNT; ++i) {
931 printf("\tfltregs[%2d] = %016llx\n",i,(unsigned long long)es->fltregs[i]);
934 #ifdef HAS_4BYTE_STACKSLOT
941 slots = code_get_stack_frame_size(code);
945 printf("\tstack slots at sp:\n");
946 for (i=0; i<slots; ++i) {
947 #ifdef HAS_4BYTE_STACKSLOT
948 printf("\t\t%08lx\n",(unsigned long)*sp++);
950 printf("\t\t%016llx\n",(unsigned long long)*sp++);
958 /* replace_sourcestate_println *************************************************
963 ss...............the source state to print
965 *******************************************************************************/
968 void replace_sourcestate_println(sourcestate *ss)
975 printf("(sourcestate *)NULL\n");
979 printf("sourcestate %p: stackbase=%p\n",(void*)ss,(void*)ss->stackbase);
981 printf("\tlocals (%d):\n",ss->javalocalcount);
982 for (i=0; i<ss->javalocalcount; ++i) {
983 for (t=0; t<5; ++t) {
984 if (ss->javalocals[i*5+t] != 0x00dead0000dead00ULL) {
985 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
986 printf("%016llx\n",(unsigned long long) ss->javalocals[i*5+t]);
993 printf("\tstack (depth %d):\n",ss->javastackdepth);
994 for (i=0; i<ss->javastackdepth; ++i) {
995 printf("\tstack[%2d] = ",i);
996 printf("%016llx\n",(unsigned long long) ss->javastack[i]);
1001 printf("\tsaved int registers (%d):\n",INT_SAV_CNT);
1003 for (i=0; i<INT_SAV_CNT; ++i) {
1004 while (nregdescint[--reg] != REG_SAV)
1006 if (ss->savedintregs[i] != 0x00dead0000dead00ULL) {
1007 printf("\t%-3s = ",regs[reg]);
1008 printf("%016llx\n",(unsigned long long) ss->savedintregs[i]);
1014 printf("\tsaved float registers (%d):\n",FLT_SAV_CNT);
1015 for (i=0; i<FLT_SAV_CNT; ++i) {
1016 if (ss->savedfltregs[i] != 0x00dead0000dead00ULL) {
1017 printf("\tsavedfltreg[%2d] = ",i);
1018 printf("%016llx\n",(unsigned long long) ss->savedfltregs[i]);
1024 printf("\tsynchronization slots (%d):\n",ss->syncslotcount);
1025 for (i=0; i<ss->syncslotcount; ++i) {
1026 printf("\tslot[%2d] = ",i);
1027 #ifdef HAS_4BYTE_STACKSLOT
1028 printf("%08lx\n",(unsigned long) ss->syncslots[i]);
1030 printf("%016llx\n",(unsigned long long) ss->syncslots[i]);
1039 * These are local overrides for various environment variables in Emacs.
1040 * Please do not remove this and leave it at the end of the file, where
1041 * Emacs will automagically detect them.
1042 * ---------------------------------------------------------------------
1045 * indent-tabs-mode: t
1049 * vim:noexpandtab:sw=4:ts=4: