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 /* replace_create_replacement_points *******************************************
52 Create the replacement points for the given code.
55 code.............codeinfo where replacement points should be stored
56 code->rplpoints must be NULL.
57 code->rplpointcount must be 0.
58 rd...............registerdata containing allocation info.
61 code->rplpoints.......set to the list of replacement points
62 code->rplpointcount...number of replacement points
63 code->regalloc........list of allocation info
64 code->regalloccount...total length of allocation info list
65 code->globalcount.....number of global allocations at the
66 start of code->regalloc
69 true.............everything ok
70 false............an exception has been thrown
72 *******************************************************************************/
74 bool replace_create_replacement_points(codeinfo *code,registerdata *rd)
90 /* assert that we wont overwrite already allocated data */
94 assert(code->rplpoints == NULL);
95 assert(code->rplpointcount == 0);
96 assert(code->regalloc == NULL);
97 assert(code->regalloccount == 0);
98 assert(code->globalcount == 0);
100 /* iterate over the basic block list to find replacement points */
106 for (bptr = m->basicblocks; bptr; bptr = bptr->next) {
107 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
110 /* there will be a replacement point at the start of this block */
113 alloccount += bptr->indepth;
116 /* if no points were found, there's nothing to do */
121 /* count global register allocations */
125 for (i=0; i<m->maxlocals; ++i) {
127 for (t=0; t<5; ++t) {
128 #if defined(ENABLE_INTRP)
131 if (rd->locals[i][t].type == t) {
135 #if defined(ENABLE_INTRP)
140 globalcount++; /* dummy rplalloc */
143 alloccount += globalcount;
145 /* allocate replacement point array and allocation array */
147 rplpoints = MNEW(rplpoint,count);
148 regalloc = MNEW(rplalloc,alloccount);
151 /* store global register allocations */
153 for (i=0; i<m->maxlocals; ++i) {
155 for (t=0; t<5; ++t) {
156 #if defined(ENABLE_INTRP)
159 if (rd->locals[i][t].type == t) {
160 ra->flags = rd->locals[i][t].flags & (INMEMORY);
161 ra->index = rd->locals[i][t].regoff;
163 ra->next = (indexused) ? 0 : 1;
167 #if defined(ENABLE_INTRP)
181 /* initialize replacement point structs */
184 for (bptr = m->basicblocks; bptr; bptr = bptr->next) {
185 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
188 /* there will be a replacement point at the start of this block */
190 rp->pc = NULL; /* set by codegen */
191 rp->outcode = NULL; /* set by codegen */
196 rp->type = bptr->type;
198 /* store local allocation info */
200 for (sp = bptr->instack; sp; sp = sp->prev) {
201 ra->flags = sp->flags & (INMEMORY);
202 ra->index = sp->regoff;
208 rp->regalloccount = ra - rp->regalloc;
213 /* store the data in the codeinfo */
215 code->rplpoints = rplpoints;
216 code->rplpointcount = count;
217 code->regalloc = regalloc;
218 code->regalloccount = alloccount;
219 code->globalcount = globalcount;
220 code->savedintcount = INT_SAV_CNT - rd->savintreguse;
221 code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
222 code->memuse = rd->memuse;
224 /* everything alright */
229 /* replace_free_replacement_points *********************************************
231 Free memory used by replacement points.
234 code.............codeinfo whose replacement points should be freed.
236 *******************************************************************************/
238 void replace_free_replacement_points(codeinfo *code)
243 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
246 MFREE(code->regalloc,rplalloc,code->regalloccount);
248 code->rplpoints = NULL;
249 code->rplpointcount = 0;
250 code->regalloc = NULL;
251 code->regalloccount = 0;
252 code->globalcount = 0;
255 /* replace_activate_replacement_point ******************************************
257 Activate a replacement point. When this function returns, the
258 replacement point is "armed", that is each thread reaching this point
259 will be replace to `target`.
262 rp...............replacement point to activate
263 target...........target of replacement
265 *******************************************************************************/
267 void replace_activate_replacement_point(rplpoint *rp,rplpoint *target)
269 assert(rp->target == NULL);
272 printf("activate replacement point: ");
273 replace_replacement_point_println(rp);
279 #if (defined(__I386__) || defined(__X86_64__)) && defined(ENABLE_JIT)
280 md_patch_replacement_point(rp);
284 /* replace_deactivate_replacement_point ****************************************
286 Deactivate a replacement point. When this function returns, the
287 replacement point is "un-armed", that is a each thread reaching this point
288 will just continue normally.
291 rp...............replacement point to deactivate
293 *******************************************************************************/
295 void replace_deactivate_replacement_point(rplpoint *rp)
300 printf("deactivate replacement point: ");
301 replace_replacement_point_println(rp);
307 #if (defined(__I386__) || defined(__X86_64__)) && defined(ENABLE_JIT)
308 md_patch_replacement_point(rp);
312 /* replace_read_executionstate *************************************************
314 Read the given executions state and translate it to a source state.
317 rp...............replacement point at which `es` was taken
318 es...............execution state
319 ss...............where to put the source state
322 *ss..............the source state derived from the execution state
324 *******************************************************************************/
326 static void replace_read_executionstate(rplpoint *rp,executionstate *es,
337 #ifdef HAS_4BYTE_STACKSLOT
349 /* calculate stack pointers */
351 #ifdef HAS_4BYTE_STACKSLOT
357 /* XXX only on i386? */
358 if (rp->type == BBTYPE_SBR)
361 basesp = sp + code_get_stack_frame_size(code);
363 /* read local variables */
365 count = m->maxlocals;
366 ss->javalocalcount = count;
367 ss->javalocals = DMNEW(u8,count * 5);
370 /* mark values as undefined */
371 for (i=0; i<count*5; ++i)
372 ss->javalocals[i] = (u8) 0x00dead0000dead00ULL;
378 for (allocs = code->globalcount; allocs--; ra++) {
383 continue; /* dummy rplalloc */
385 #ifdef HAS_4BYTE_STACKSLOT
386 if (IS_2_WORD_TYPE(ra->type)) {
387 if (ra->flags & INMEMORY) {
388 ss->javalocals[i*5+t] = *(u8*)(sp + ra->index);
391 dolog("XXX split 2-word types in registers are not supported");
397 if (ra->flags & INMEMORY) {
398 ss->javalocals[i*5+t] = sp[ra->index];
401 ss->javalocals[i*5+t] = es->intregs[ra->index];
403 #ifdef HAS_4BYTE_STACKSLOT
408 /* read stack slots */
410 count = rp->regalloccount;
411 ss->javastackdepth = count;
412 ss->javastack = DMNEW(u8,count);
417 /* the first stack slot is special in SBR and EXH blocks */
419 if (rp->type == BBTYPE_SBR) {
422 ss->javastack[i] = sp[-1];
427 else if (rp->type == BBTYPE_EXH) {
430 ss->javastack[i] = es->intregs[REG_ITMP1]; /* XXX all platforms? */
436 for (; count--; ra++, i++) {
439 if (ra->flags & INMEMORY) {
440 ss->javastack[i] = sp[ra->index];
443 ss->javastack[i] = es->intregs[ra->index];
447 /* read unused callee saved int regs */
450 for (i=0; count > code->savedintcount; ++i) {
451 assert(i < INT_REG_CNT);
452 if (nregdescint[i] == REG_SAV)
453 ss->savedintregs[--count] = es->intregs[i];
456 /* read saved int regs */
458 for (i=0; i<code->savedintcount; ++i) {
459 ss->savedintregs[i] = *--basesp;
462 /* read saved flt regs */
464 for (i=0; i<code->savedfltcount; ++i) {
465 #ifdef HAS_4BYTE_STACKSLOT
470 ss->savedfltregs[i] = *(u8*)basesp;
473 /* read unused callee saved flt regs */
476 for (i=0; count > code->savedfltcount; ++i) {
477 assert(i < FLT_REG_CNT);
478 if (nregdescfloat[i] == REG_SAV)
479 ss->savedfltregs[--count] = es->fltregs[i];
482 /* read slots used for synchronization */
484 count = code_get_sync_slot_count(code);
485 ss->syncslotcount = count;
486 ss->syncslots = DMNEW(u8,count);
487 for (i=0; i<count; ++i) {
488 ss->syncslots[i] = *--basesp;
492 /* replace_write_executionstate ************************************************
494 Translate the given source state into an execution state.
497 rp...............replacement point for which execution state should be
499 es...............where to put the execution state
500 ss...............the given source state
503 *es..............the execution state derived from the source state
505 *******************************************************************************/
507 static void replace_write_executionstate(rplpoint *rp,executionstate *es,sourcestate *ss)
517 #ifdef HAS_4BYTE_STACKSLOT
529 /* calculate stack pointers */
531 #ifdef HAS_4BYTE_STACKSLOT
537 if (rp->type == BBTYPE_SBR)
540 basesp = sp + code_get_stack_frame_size(code);
542 /* in debug mode, invalidate stack frame first */
545 for (i=0; i<(basesp - sp); ++i) {
550 /* write local variables */
552 count = m->maxlocals;
557 for (allocs = code->globalcount; allocs--; ra++) {
561 assert(i >= 0 && i < m->maxlocals);
565 continue; /* dummy rplalloc */
567 #ifdef HAS_4BYTE_STACKSLOT
568 if (IS_2_WORD_TYPE(ra->type)) {
569 if (ra->flags & INMEMORY) {
570 *(u8*)(sp + ra->index) = ss->javalocals[i*5+t];
573 dolog("XXX split 2-word types in registers are not supported");
579 if (ra->flags & INMEMORY) {
580 sp[ra->index] = ss->javalocals[i*5+t];
583 es->intregs[ra->index] = ss->javalocals[i*5+t];
585 #ifdef HAS_4BYTE_STACKSLOT
590 /* write stack slots */
592 count = rp->regalloccount;
597 /* the first stack slot is special in SBR and EXH blocks */
599 if (rp->type == BBTYPE_SBR) {
602 sp[-1] = ss->javastack[i];
607 else if (rp->type == BBTYPE_EXH) {
610 es->intregs[REG_ITMP1] = ss->javastack[i]; /* XXX all platforms? */
616 for (; count--; ra++, i++) {
619 if (ra->flags & INMEMORY) {
620 sp[ra->index] = ss->javastack[i];
623 es->intregs[ra->index] = ss->javastack[i];
627 /* write unused callee saved int regs */
630 for (i=0; count > code->savedintcount; ++i) {
631 assert(i < INT_REG_CNT);
632 if (nregdescint[i] == REG_SAV)
633 es->intregs[i] = ss->savedintregs[--count];
636 /* write saved int regs */
638 for (i=0; i<code->savedintcount; ++i) {
639 *--basesp = ss->savedintregs[i];
642 /* write unused callee saved flt regs */
645 for (i=0; count > code->savedfltcount; ++i) {
646 assert(i < FLT_REG_CNT);
647 if (nregdescfloat[i] == REG_SAV)
648 es->fltregs[i] = ss->savedfltregs[--count];
651 /* write saved flt regs */
653 for (i=0; i<code->savedfltcount; ++i) {
654 #ifdef HAS_4BYTE_STACKSLOT
659 *(u8*)basesp = ss->savedfltregs[i];
662 /* write slots used for synchronization */
664 count = code_get_sync_slot_count(code);
665 assert(count == ss->syncslotcount);
666 for (i=0; i<count; ++i) {
667 *--basesp = ss->syncslots[i];
675 /* replace_me ******************************************************************
677 This function is called by asm_replacement_out when a thread reaches
678 a replacement point. `replace_me` must map the execution state to the
679 target replacement point and let execution continue there.
681 This function never returns!
684 rp...............replacement point that has been reached
685 es...............execution state read by asm_replacement_out
687 *******************************************************************************/
689 void replace_me(rplpoint *rp,executionstate *es)
695 /* mark start of dump memory area */
697 dumpsize = dump_size();
699 /* fetch the target of the replacement */
703 /* XXX DEBUG turn of self-replacement */
705 replace_deactivate_replacement_point(rp);
708 printf("replace_me(%p,%p)\n",(void*)rp,(void*)es);
710 replace_replacement_point_println(rp);
711 replace_executionstate_println(es,rp->code);
714 /* read execution state of old code */
716 replace_read_executionstate(rp,es,&ss);
719 replace_sourcestate_println(&ss);
722 /* write execution state of new code */
724 replace_write_executionstate(target,es,&ss);
727 replace_executionstate_println(es,target->code);
730 /* release dump area */
732 dump_release(dumpsize);
736 #if (defined(__I386__) || defined(__X86_64__)) && defined(ENABLE_JIT)
737 asm_replacement_in(es);
742 /* replace_replacement_point_println *******************************************
744 Print replacement point info.
747 rp...............the replacement point to print
749 *******************************************************************************/
752 static const char *type_char = "IJFDA";
754 #define TYPECHAR(t) (((t) >= 0 && (t) <= 4) ? type_char[t] : '?')
756 void replace_replacement_point_println(rplpoint *rp)
761 printf("(rplpoint *)NULL\n");
765 printf("rplpoint %p pc:%p out:%p target:%p mcode:%016llx type:%01d flags:%01x ra:%d = [",
766 (void*)rp,rp->pc,rp->outcode,(void*)rp->target,
767 (unsigned long long)rp->mcode,rp->type,rp->flags,rp->regalloccount);
769 for (j=0; j<rp->regalloccount; ++j)
770 printf("%c%1c%01x:%02d",
771 (rp->regalloc[j].next) ? '^' : ' ',
772 TYPECHAR(rp->regalloc[j].type),
773 rp->regalloc[j].flags,
774 rp->regalloc[j].index);
776 printf("]\n method: ");
777 method_print(rp->code->m);
783 /* replace_show_replacement_points *********************************************
785 Print replacement point info.
788 code.............codeinfo whose replacement points should be printed.
790 *******************************************************************************/
793 void replace_show_replacement_points(codeinfo *code)
799 printf("(codeinfo *)NULL\n");
803 printf("\treplacement points: %d\n",code->rplpointcount);
804 printf("\tglobal allocations: %d = [",code->globalcount);
806 for (i=0; i<code->globalcount; ++i)
807 printf("%c%1c%01x:%02d",
808 (code->regalloc[i].next) ? '^' : ' ',
809 TYPECHAR(code->regalloc[i].type),
810 code->regalloc[i].flags,code->regalloc[i].index);
814 printf("\ttotal allocations : %d\n",code->regalloccount);
815 printf("\tsaved int regs : %d\n",code->savedintcount);
816 printf("\tsaved flt regs : %d\n",code->savedfltcount);
817 printf("\tmemuse : %d\n",code->memuse);
821 for (i=0; i<code->rplpointcount; ++i) {
822 rp = code->rplpoints + i;
824 assert(rp->code == code);
827 replace_replacement_point_println(rp);
832 /* replace_executionstate_println **********************************************
834 Print execution state
837 es...............the execution state to print
838 code.............the codeinfo for which this execution state is meant
841 *******************************************************************************/
844 void replace_executionstate_println(executionstate *es,codeinfo *code)
848 #ifdef HAS_4BYTE_STACKSLOT
855 printf("(executionstate *)NULL\n");
859 printf("executionstate %p:\n",(void*)es);
860 printf("\tpc = %p\n",(void*)es->pc);
861 printf("\tsp = %p\n",(void*)es->sp);
862 for (i=0; i<INT_REG_CNT; ++i) {
863 printf("\t%-3s = %016llx\n",regs[i],(unsigned long long)es->intregs[i]);
865 for (i=0; i<FLT_REG_CNT; ++i) {
866 printf("\tfltregs[%2d] = %016llx\n",i,(unsigned long long)es->fltregs[i]);
869 #ifdef HAS_4BYTE_STACKSLOT
876 slots = code_get_stack_frame_size(code);
880 printf("\tstack slots at sp:\n");
881 for (i=0; i<slots; ++i) {
882 #ifdef HAS_4BYTE_STACKSLOT
883 printf("\t\t%08lx\n",(unsigned long)*sp++);
885 printf("\t\t%016llx\n",(unsigned long long)*sp++);
893 /* replace_sourcestate_println *************************************************
898 ss...............the source state to print
900 *******************************************************************************/
903 void replace_sourcestate_println(sourcestate *ss)
910 printf("(sourcestate *)NULL\n");
914 printf("sourcestate %p:\n",(void*)ss);
916 printf("\tlocals (%d):\n",ss->javalocalcount);
917 for (i=0; i<ss->javalocalcount; ++i) {
918 for (t=0; t<5; ++t) {
919 if (ss->javalocals[i*5+t] != 0x00dead0000dead00ULL) {
920 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
921 printf("%016llx\n",(unsigned long long) ss->javalocals[i*5+t]);
928 printf("\tstack (depth %d):\n",ss->javastackdepth);
929 for (i=0; i<ss->javastackdepth; ++i) {
930 printf("\tstack[%2d] = ",i);
931 printf("%016llx\n",(unsigned long long) ss->javastack[i]);
936 printf("\tsaved int registers (%d):\n",INT_SAV_CNT);
938 for (i=0; i<INT_SAV_CNT; ++i) {
939 while (nregdescint[--reg] != REG_SAV)
941 if (ss->savedintregs[i] != 0x00dead0000dead00ULL) {
942 printf("\t%-3s = ",regs[reg]);
943 printf("%016llx\n",(unsigned long long) ss->savedintregs[i]);
949 printf("\tsaved float registers (%d):\n",FLT_SAV_CNT);
950 for (i=0; i<FLT_SAV_CNT; ++i) {
951 if (ss->savedfltregs[i] != 0x00dead0000dead00ULL) {
952 printf("\tsavedfltreg[%2d] = ",i);
953 printf("%016llx\n",(unsigned long long) ss->savedfltregs[i]);
959 printf("\tsynchronization slots (%d):\n",ss->syncslotcount);
960 for (i=0; i<ss->syncslotcount; ++i) {
961 printf("\tslot[%2d] = ",i);
962 #ifdef HAS_4BYTE_STACKSLOT
963 printf("%08lx\n",(unsigned long) ss->syncslots[i]);
965 printf("%016llx\n",(unsigned long long) ss->syncslots[i]);
974 * These are local overrides for various environment variables in Emacs.
975 * Please do not remove this and leave it at the end of the file, where
976 * Emacs will automagically detect them.
977 * ---------------------------------------------------------------------
980 * indent-tabs-mode: t
984 * vim:noexpandtab:sw=4:ts=4: