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;
230 /* everything alright */
235 /* replace_free_replacement_points *********************************************
237 Free memory used by replacement points.
240 code.............codeinfo whose replacement points should be freed.
242 *******************************************************************************/
244 void replace_free_replacement_points(codeinfo *code)
249 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
252 MFREE(code->regalloc,rplalloc,code->regalloccount);
254 code->rplpoints = NULL;
255 code->rplpointcount = 0;
256 code->regalloc = NULL;
257 code->regalloccount = 0;
258 code->globalcount = 0;
261 /* replace_activate_replacement_point ******************************************
263 Activate a replacement point. When this function returns, the
264 replacement point is "armed", that is each thread reaching this point
265 will be replace to `target`.
268 rp...............replacement point to activate
269 target...........target of replacement
271 *******************************************************************************/
273 void replace_activate_replacement_point(rplpoint *rp,rplpoint *target)
275 assert(rp->target == NULL);
278 printf("activate replacement point: ");
279 replace_replacement_point_println(rp);
285 #if (defined(__I386__) || defined(__X86_64__)) && defined(ENABLE_JIT)
286 md_patch_replacement_point(rp);
290 /* replace_deactivate_replacement_point ****************************************
292 Deactivate a replacement point. When this function returns, the
293 replacement point is "un-armed", that is a each thread reaching this point
294 will just continue normally.
297 rp...............replacement point to deactivate
299 *******************************************************************************/
301 void replace_deactivate_replacement_point(rplpoint *rp)
306 printf("deactivate replacement point: ");
307 replace_replacement_point_println(rp);
313 #if (defined(__I386__) || defined(__X86_64__)) && defined(ENABLE_JIT)
314 md_patch_replacement_point(rp);
318 /* replace_read_executionstate *************************************************
320 Read the given executions state and translate it to a source state.
323 rp...............replacement point at which `es` was taken
324 es...............execution state
325 ss...............where to put the source state
328 *ss..............the source state derived from the execution state
330 *******************************************************************************/
332 static void replace_read_executionstate(rplpoint *rp,executionstate *es,
344 #ifdef HAS_4BYTE_STACKSLOT
355 topslot = TOP_IS_NORMAL;
359 #ifdef HAS_4BYTE_STACKSLOT
365 /* on some architectures the returnAddress is passed on the stack by JSR */
367 #if defined(__I386__) || defined(__X86_64__)
368 if (rp->type == BBTYPE_SBR) {
370 topslot = TOP_IS_ON_STACK;
374 /* in some cases the top stack slot is passed in REG_ITMP1 */
376 if ( (rp->type == BBTYPE_EXH)
377 #if defined(__ALPHA__)
378 || (rp->type == BBTYPE_SBR)
382 topslot = TOP_IS_IN_ITMP1;
385 /* calculate base stack pointer */
387 basesp = sp + code_get_stack_frame_size(code);
389 ss->stackbase = (u1*) basesp;
391 /* read local variables */
393 count = m->maxlocals;
394 ss->javalocalcount = count;
395 ss->javalocals = DMNEW(u8,count * 5);
398 /* mark values as undefined */
399 for (i=0; i<count*5; ++i)
400 ss->javalocals[i] = (u8) 0x00dead0000dead00ULL;
402 /* some entries in the intregs array are not meaningful */
403 es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;
404 es->intregs[REG_SP ] = (u8) 0x11dead1111dead11ULL;
406 es->intregs[REG_PV ] = (u8) 0x11dead1111dead11ULL;
413 for (allocs = code->globalcount; allocs--; ra++) {
418 continue; /* dummy rplalloc */
420 #ifdef HAS_4BYTE_STACKSLOT
421 if (IS_2_WORD_TYPE(ra->type)) {
422 if (ra->flags & INMEMORY) {
423 ss->javalocals[i*5+t] = *(u8*)(sp + ra->index);
426 dolog("XXX split 2-word types in registers are not supported");
432 if (ra->flags & INMEMORY) {
433 ss->javalocals[i*5+t] = sp[ra->index];
436 ss->javalocals[i*5+t] = es->intregs[ra->index];
438 #ifdef HAS_4BYTE_STACKSLOT
443 /* read stack slots */
445 count = rp->regalloccount;
446 ss->javastackdepth = count;
447 ss->javastack = DMNEW(u8,count);
450 /* mark values as undefined */
451 for (i=0; i<count; ++i)
452 ss->javastack[i] = (u8) 0x00dead0000dead00ULL;
458 /* the first stack slot is special in SBR and EXH blocks */
460 if (topslot == TOP_IS_ON_STACK) {
463 ss->javastack[i] = sp[-1];
468 else if (topslot == TOP_IS_IN_ITMP1) {
471 ss->javastack[i] = es->intregs[REG_ITMP1];
477 /* read remaining stack slots */
479 for (; count--; ra++, i++) {
482 if (ra->flags & INMEMORY) {
483 ss->javastack[i] = sp[ra->index];
486 ss->javastack[i] = es->intregs[ra->index];
490 /* read unused callee saved int regs */
493 for (i=0; count > code->savedintcount; ++i) {
494 assert(i < INT_REG_CNT);
495 if (nregdescint[i] == REG_SAV)
496 ss->savedintregs[--count] = es->intregs[i];
499 /* read saved int regs */
501 for (i=0; i<code->savedintcount; ++i) {
502 ss->savedintregs[i] = *--basesp;
505 /* read unused callee saved flt regs */
508 for (i=0; count > code->savedfltcount; ++i) {
509 assert(i < FLT_REG_CNT);
510 if (nregdescfloat[i] == REG_SAV)
511 ss->savedfltregs[--count] = es->fltregs[i];
514 /* read saved flt regs */
516 for (i=0; i<code->savedfltcount; ++i) {
517 #ifdef HAS_4BYTE_STACKSLOT
522 ss->savedfltregs[i] = *(u8*)basesp;
525 /* read slots used for synchronization */
527 count = code_get_sync_slot_count(code);
528 ss->syncslotcount = count;
529 ss->syncslots = DMNEW(u8,count);
530 for (i=0; i<count; ++i) {
531 ss->syncslots[i] = *--basesp;
535 /* replace_write_executionstate ************************************************
537 Translate the given source state into an execution state.
540 rp...............replacement point for which execution state should be
542 es...............where to put the execution state
543 ss...............the given source state
546 *es..............the execution state derived from the source state
548 *******************************************************************************/
550 static void replace_write_executionstate(rplpoint *rp,executionstate *es,
562 #ifdef HAS_4BYTE_STACKSLOT
574 /* calculate stack pointer */
576 #ifdef HAS_4BYTE_STACKSLOT
577 basesp = (u4*) ss->stackbase;
579 basesp = (u8*) ss->stackbase;
582 sp = basesp - code_get_stack_frame_size(code);
584 /* on some architectures the returnAddress is passed on the stack by JSR */
586 #if defined(__I386__) || defined(__X86_64__)
587 if (rp->type == BBTYPE_SBR) {
588 topslot = TOP_IS_ON_STACK;
592 /* in some cases the top stack slot is passed in REG_ITMP1 */
594 if ( (rp->type == BBTYPE_EXH)
595 #if defined(__ALPHA__)
596 || (rp->type == BBTYPE_SBR)
600 topslot = TOP_IS_IN_ITMP1;
603 /* in debug mode, invalidate stack frame first */
606 for (i=0; i<(basesp - sp); ++i) {
611 /* write local variables */
613 count = m->maxlocals;
618 for (allocs = code->globalcount; allocs--; ra++) {
622 assert(i >= 0 && i < m->maxlocals);
626 continue; /* dummy rplalloc */
628 #ifdef HAS_4BYTE_STACKSLOT
629 if (IS_2_WORD_TYPE(ra->type)) {
630 if (ra->flags & INMEMORY) {
631 *(u8*)(sp + ra->index) = ss->javalocals[i*5+t];
634 dolog("XXX split 2-word types in registers are not supported");
640 if (ra->flags & INMEMORY) {
641 sp[ra->index] = ss->javalocals[i*5+t];
644 es->intregs[ra->index] = ss->javalocals[i*5+t];
646 #ifdef HAS_4BYTE_STACKSLOT
651 /* write stack slots */
653 count = rp->regalloccount;
658 /* the first stack slot is special in SBR and EXH blocks */
660 if (topslot == TOP_IS_ON_STACK) {
663 sp[-1] = ss->javastack[i];
668 else if (topslot == TOP_IS_IN_ITMP1) {
671 es->intregs[REG_ITMP1] = ss->javastack[i];
677 /* write remaining stack slots */
679 for (; count--; ra++, i++) {
682 if (ra->flags & INMEMORY) {
683 sp[ra->index] = ss->javastack[i];
686 es->intregs[ra->index] = ss->javastack[i];
690 /* write unused callee saved int regs */
693 for (i=0; count > code->savedintcount; ++i) {
694 assert(i < INT_REG_CNT);
695 if (nregdescint[i] == REG_SAV)
696 es->intregs[i] = ss->savedintregs[--count];
699 /* write saved int regs */
701 for (i=0; i<code->savedintcount; ++i) {
702 *--basesp = ss->savedintregs[i];
705 /* write unused callee saved flt regs */
708 for (i=0; count > code->savedfltcount; ++i) {
709 assert(i < FLT_REG_CNT);
710 if (nregdescfloat[i] == REG_SAV)
711 es->fltregs[i] = ss->savedfltregs[--count];
714 /* write saved flt regs */
716 for (i=0; i<code->savedfltcount; ++i) {
717 #ifdef HAS_4BYTE_STACKSLOT
722 *(u8*)basesp = ss->savedfltregs[i];
725 /* write slots used for synchronization */
727 count = code_get_sync_slot_count(code);
728 assert(count == ss->syncslotcount);
729 for (i=0; i<count; ++i) {
730 *--basesp = ss->syncslots[i];
738 /* replace_me ******************************************************************
740 This function is called by asm_replacement_out when a thread reaches
741 a replacement point. `replace_me` must map the execution state to the
742 target replacement point and let execution continue there.
744 This function never returns!
747 rp...............replacement point that has been reached
748 es...............execution state read by asm_replacement_out
750 *******************************************************************************/
752 void replace_me(rplpoint *rp,executionstate *es)
758 /* mark start of dump memory area */
760 dumpsize = dump_size();
762 /* fetch the target of the replacement */
766 /* XXX DEBUG turn of self-replacement */
768 replace_deactivate_replacement_point(rp);
771 printf("replace_me(%p,%p)\n",(void*)rp,(void*)es);
773 replace_replacement_point_println(rp);
774 replace_executionstate_println(es,rp->code);
777 /* read execution state of old code */
779 replace_read_executionstate(rp,es,&ss);
782 replace_sourcestate_println(&ss);
785 /* write execution state of new code */
787 replace_write_executionstate(target,es,&ss);
790 replace_executionstate_println(es,target->code);
793 /* release dump area */
795 dump_release(dumpsize);
799 #if (defined(__I386__) || defined(__X86_64__)) && defined(ENABLE_JIT)
800 asm_replacement_in(es);
805 /* replace_replacement_point_println *******************************************
807 Print replacement point info.
810 rp...............the replacement point to print
812 *******************************************************************************/
815 static const char *type_char = "IJFDA";
817 #define TYPECHAR(t) (((t) >= 0 && (t) <= 4) ? type_char[t] : '?')
819 void replace_replacement_point_println(rplpoint *rp)
824 printf("(rplpoint *)NULL\n");
828 printf("rplpoint %p pc:%p out:%p target:%p mcode:%016llx type:%01d flags:%01x ra:%d = [",
829 (void*)rp,rp->pc,rp->outcode,(void*)rp->target,
830 (unsigned long long)rp->mcode,rp->type,rp->flags,rp->regalloccount);
832 for (j=0; j<rp->regalloccount; ++j)
833 printf("%c%1c%01x:%02d",
834 (rp->regalloc[j].next) ? '^' : ' ',
835 TYPECHAR(rp->regalloc[j].type),
836 rp->regalloc[j].flags,
837 rp->regalloc[j].index);
839 printf("]\n method: ");
840 method_print(rp->code->m);
846 /* replace_show_replacement_points *********************************************
848 Print replacement point info.
851 code.............codeinfo whose replacement points should be printed.
853 *******************************************************************************/
856 void replace_show_replacement_points(codeinfo *code)
862 printf("(codeinfo *)NULL\n");
866 printf("\treplacement points: %d\n",code->rplpointcount);
867 printf("\tglobal allocations: %d = [",code->globalcount);
869 for (i=0; i<code->globalcount; ++i)
870 printf("%c%1c%01x:%02d",
871 (code->regalloc[i].next) ? '^' : ' ',
872 TYPECHAR(code->regalloc[i].type),
873 code->regalloc[i].flags,code->regalloc[i].index);
877 printf("\ttotal allocations : %d\n",code->regalloccount);
878 printf("\tsaved int regs : %d\n",code->savedintcount);
879 printf("\tsaved flt regs : %d\n",code->savedfltcount);
880 printf("\tmemuse : %d\n",code->memuse);
884 for (i=0; i<code->rplpointcount; ++i) {
885 rp = code->rplpoints + i;
887 assert(rp->code == code);
890 replace_replacement_point_println(rp);
895 /* replace_executionstate_println **********************************************
897 Print execution state
900 es...............the execution state to print
901 code.............the codeinfo for which this execution state is meant
904 *******************************************************************************/
907 void replace_executionstate_println(executionstate *es,codeinfo *code)
911 #ifdef HAS_4BYTE_STACKSLOT
918 printf("(executionstate *)NULL\n");
922 printf("executionstate %p:\n",(void*)es);
923 printf("\tpc = %p\n",(void*)es->pc);
924 printf("\tsp = %p\n",(void*)es->sp);
925 printf("\tpv = %p\n",(void*)es->pv);
926 for (i=0; i<INT_REG_CNT; ++i) {
927 printf("\t%-3s = %016llx\n",regs[i],(unsigned long long)es->intregs[i]);
929 for (i=0; i<FLT_REG_CNT; ++i) {
930 printf("\tfltregs[%2d] = %016llx\n",i,(unsigned long long)es->fltregs[i]);
933 #ifdef HAS_4BYTE_STACKSLOT
940 slots = code_get_stack_frame_size(code);
944 printf("\tstack slots at sp:\n");
945 for (i=0; i<slots; ++i) {
946 #ifdef HAS_4BYTE_STACKSLOT
947 printf("\t\t%08lx\n",(unsigned long)*sp++);
949 printf("\t\t%016llx\n",(unsigned long long)*sp++);
957 /* replace_sourcestate_println *************************************************
962 ss...............the source state to print
964 *******************************************************************************/
967 void replace_sourcestate_println(sourcestate *ss)
974 printf("(sourcestate *)NULL\n");
978 printf("sourcestate %p: stackbase=%p\n",(void*)ss,(void*)ss->stackbase);
980 printf("\tlocals (%d):\n",ss->javalocalcount);
981 for (i=0; i<ss->javalocalcount; ++i) {
982 for (t=0; t<5; ++t) {
983 if (ss->javalocals[i*5+t] != 0x00dead0000dead00ULL) {
984 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
985 printf("%016llx\n",(unsigned long long) ss->javalocals[i*5+t]);
992 printf("\tstack (depth %d):\n",ss->javastackdepth);
993 for (i=0; i<ss->javastackdepth; ++i) {
994 printf("\tstack[%2d] = ",i);
995 printf("%016llx\n",(unsigned long long) ss->javastack[i]);
1000 printf("\tsaved int registers (%d):\n",INT_SAV_CNT);
1002 for (i=0; i<INT_SAV_CNT; ++i) {
1003 while (nregdescint[--reg] != REG_SAV)
1005 if (ss->savedintregs[i] != 0x00dead0000dead00ULL) {
1006 printf("\t%-3s = ",regs[reg]);
1007 printf("%016llx\n",(unsigned long long) ss->savedintregs[i]);
1013 printf("\tsaved float registers (%d):\n",FLT_SAV_CNT);
1014 for (i=0; i<FLT_SAV_CNT; ++i) {
1015 if (ss->savedfltregs[i] != 0x00dead0000dead00ULL) {
1016 printf("\tsavedfltreg[%2d] = ",i);
1017 printf("%016llx\n",(unsigned long long) ss->savedfltregs[i]);
1023 printf("\tsynchronization slots (%d):\n",ss->syncslotcount);
1024 for (i=0; i<ss->syncslotcount; ++i) {
1025 printf("\tslot[%2d] = ",i);
1026 #ifdef HAS_4BYTE_STACKSLOT
1027 printf("%08lx\n",(unsigned long) ss->syncslots[i]);
1029 printf("%016llx\n",(unsigned long long) ss->syncslots[i]);
1038 * These are local overrides for various environment variables in Emacs.
1039 * Please do not remove this and leave it at the end of the file, where
1040 * Emacs will automagically detect them.
1041 * ---------------------------------------------------------------------
1044 * indent-tabs-mode: t
1048 * vim:noexpandtab:sw=4:ts=4: