1 /* src/vm/jit/inline/inline.c - code inliner
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
31 $Id: inline.c 4670 2006-03-22 01:22:11Z edwin $
44 #include "mm/memory.h"
45 #include "toolbox/logging.h"
46 #include "vm/global.h"
47 #include "vm/options.h"
48 #include "vm/statistics.h"
49 #include "vm/jit/jit.h"
50 #include "vm/jit/parse.h"
51 #include "vm/jit/inline/inline.h"
52 #include "vm/jit/loop/loop.h"
55 #include "vm/initialize.h"
56 #include "vm/method.h"
57 #include "vm/jit/jit.h"
59 #include "vm/jit/reg.h"
60 #include "vm/jit/stack.h"
62 #include "vm/jit/verify/typecheck.h"
64 #if defined(USE_THREADS)
65 # if defined(NATIVE_THREADS)
66 # include "threads/native/threads.h"
68 # include "threads/green/threads.h"
73 bool inline_debug_log = 0;
74 bool inline_debug_log_names = 0;
75 int inline_debug_start_counter = 0;
76 int inline_debug_max_size = INT_MAX;
77 int inline_debug_min_size = 0;
78 int inline_debug_end_counter = INT_MAX;
79 int inline_count_methods = 0;
80 #define DOLOG(code) do{ if (inline_debug_log) { code; } }while(0)
85 typedef struct inline_node inline_node;
86 typedef struct inline_target_ref inline_target_ref;
87 typedef struct inline_context inline_context;
88 typedef struct inline_stack_translation inline_stack_translation;
89 typedef struct inline_block_map inline_block_map;
95 inline_node *children;
100 /* info about the call site (if depth > 0)*/
102 basicblock *callerblock;
103 instruction *callerins;
105 stackptr n_callerstack;
106 int n_callerstackdepth;
107 stackptr o_callerstack;
109 /* info about the callee */
111 int prolog_instructioncount;
112 int instructioncount;
115 /* cumulative values */
116 int cumul_instructioncount;
117 int cumul_stackcount;
118 int cumul_basicblockcount;
121 int cumul_exceptiontablelength;
124 instruction *inlined_iinstr;
125 instruction *inlined_iinstr_cursor;
126 stackptr n_inlined_stack;
127 stackptr n_inlined_stack_cursor;
128 basicblock *inlined_basicblocks;
129 basicblock *inlined_basicblocks_cursor;
132 registerdata *regdata;
135 inline_target_ref *refs;
136 instruction *inline_start_instruction;
139 struct inline_target_ref {
140 inline_target_ref *next;
145 struct inline_stack_translation {
150 struct inline_block_map {
156 struct inline_context {
157 int next_block_number;
159 inline_block_map *blockmap;
162 stackptr o_translationlimit; /* if a stackptr is smaller than this, look it up in the table */
163 stackptr n_debug_stackbase;
164 inline_stack_translation *stacktranslationstart;
166 inline_stack_translation stacktranslation[1];
169 #include "inline_debug.c"
171 void inline_print_stats()
173 printf("inlined callers: %d\n",inline_count_methods);
176 static bool inline_jit_compile_intern(methodinfo *m, codegendata *cd, registerdata *rd,
184 /* XXX initialize the static function's class */
186 m->isleafmethod = true;
188 /* call the compiler passes ***********************************************/
190 /* call parse pass */
192 DOLOG( log_message_class("Parsing ", m->class) );
197 /* call stack analysis pass */
199 if (!analyse_stack(m, cd, rd)) {
206 static bool inline_jit_compile(inline_node *iln)
219 #if defined(USE_THREADS)
220 /* enter a monitor on the method */
221 builtin_monitorenter((java_objectheader *) m);
224 /* XXX dont parse these a second time because parse is not idempotent */
225 for (i=0; i<m->jcodelength; ++i) {
226 if (m->jcode[i] == JAVA_TABLESWITCH || m->jcode[i] == JAVA_LOOKUPSWITCH) {
232 /* allocate memory */
233 cd = DNEW(codegendata);
234 rd = DNEW(registerdata);
237 #if defined(ENABLE_JIT)
238 # if defined(ENABLE_INTRP)
241 /* initialize the register allocator */
245 /* setup the codegendata memory */
247 codegen_setup(m, cd);
249 /* now call internal compile function */
251 r = inline_jit_compile_intern(m, cd, rd, ld);
257 /* free some memory */
261 #if defined(ENABLE_JIT)
262 # if defined(ENABLE_INTRP)
271 #if defined(USE_THREADS)
272 /* leave the monitor */
273 builtin_monitorexit((java_objectheader *) m );
279 static void insert_inline_node(inline_node *parent,inline_node *child)
284 assert(parent && child);
286 child->parent = parent;
288 first = parent->children;
290 /* insert as only node */
291 parent->children = child;
297 /* {there is at least one child already there} */
300 while (succ->callerpc < child->callerpc) {
303 /* insert as last node */
304 child->prev = first->prev;
306 child->prev->next = child;
307 child->next->prev = child;
312 assert(succ->callerpc > child->callerpc);
314 /* insert before succ */
316 child->prev = succ->prev;
318 child->prev->next = child;
319 child->next->prev = child;
322 static stackptr relocate_stack_ptr_intern(inline_node *iln,stackptr o_link,ptrint curreloc)
324 inline_stack_translation *tr;
327 /* XXX should limit range in both directions */
328 if (o_link < iln->ctx->o_translationlimit) {
329 /* this stack slot is from an earlier chunk, we must look it up */
330 tr = iln->ctx->stacktranslationstart;
331 while (tr >= iln->ctx->stacktranslation) {
332 if (o_link == tr->o_sp) {
333 DOLOG(printf("\t\t\ttable lookup %p -> %d\n",(void*)o_link,DEBUG_SLOT(tr->n_sp)));
338 DOLOG(debug_dump_inline_context(iln));
339 DOLOG(printf("\t\tFAILED TO TRANSLATE: %p\n",(void*)o_link));
343 /* this stack slot it in the most recent chunk */
345 DOLOG( printf("\t\t\toffset %d\n",(int)curreloc) );
346 return (stackptr) ((u1*)o_link + curreloc);
349 return iln->n_callerstack;
352 /* XXX for debugging */
353 static stackptr relocate_stack_ptr(inline_node *iln,stackptr o_link,ptrint curreloc)
357 new = relocate_stack_ptr_intern(iln,o_link,curreloc);
359 printf("\t\treloc %p -> %d (%p)\t(translimit=%p)\n",
360 (void*)o_link,DEBUG_SLOT(new),(void*)new,(void*)iln->ctx->o_translationlimit)
365 static void emit_instruction(inline_node *iln,instruction *ins,ptrint curreloc,stackptr o_curstack)
370 inline_target_ref *ref;
374 for (i=0; i<iln->depth; ++i)
378 n_ins = (iln->inlined_iinstr_cursor++);
379 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
383 switch (n_ins[0].opc) {
384 /****************************************/
385 /* VARIABLE ACCESS */
399 n_ins[0].op1 += iln->localsoffset;
432 ref = DNEW(inline_target_ref);
433 ref->ref = (basicblock **) &(n_ins[0].target);
434 ref->next = iln->refs;
438 /****************************************/
443 n_ins[0].opc = ICMD_GOTO;
455 n_ins[0].opc = ICMD_INLINE_GOTO;
456 n_ins[0].dst = o_curstack;
458 n_ins[0].target = (void *) (ptrint) (iln->depth + 0x333); /* XXX */
459 ref = DNEW(inline_target_ref);
460 ref->ref = (basicblock **) &(n_ins[0].target);
461 ref->next = iln->refs;
467 n_ins[0].dst = relocate_stack_ptr(iln,n_ins[0].dst,curreloc);
470 static stackptr emit_inlining_prolog(inline_node *iln,inline_node *callee,stackptr n_curstack,instruction *o_iptr)
480 assert(iln && callee && o_iptr && o_iptr->method == iln->m);
483 md = calleem->parseddesc;
485 localindex = callee->localsoffset + md->paramslots;
486 depth = stack_depth(n_curstack) - 1; /* XXX inefficient */
487 for (i=md->paramcount-1; i>=0; --i) {
490 n_ins = (iln->inlined_iinstr_cursor++);
491 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
493 type = md->paramtypes[i].type;
495 localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
496 assert(callee->regdata);
498 DOLOG( printf("prologlocal %d type=%d lofs=%d in ",
499 localindex - callee->localsoffset,
500 callee->regdata->locals[localindex - callee->localsoffset][type].type,callee->localsoffset);
501 method_println(callee->m); );
503 if (callee->regdata->locals[localindex - callee->localsoffset][type].type >= 0) {
504 n_ins->opc = ICMD_ISTORE + type;
505 n_ins->op1 = localindex;
508 n_ins->opc = IS_2_WORD_TYPE(type) ? ICMD_POP2 : ICMD_POP;
510 n_ins->method = iln->m;
511 n_ins->line = o_iptr->line;
513 if (n_curstack->varkind == ARGVAR) {
514 n_curstack->varkind = TEMPVAR;
515 n_curstack->varnum = depth;
516 n_curstack->flags &= ~INMEMORY;
518 n_curstack = n_curstack->prev;
519 n_ins->dst = n_curstack;
523 n_ins = (iln->inlined_iinstr_cursor++);
524 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
526 n_ins->opc = ICMD_INLINE_START;
527 n_ins->method = callee->m;
528 n_ins->dst = n_curstack;
529 n_ins->line = o_iptr->line;
530 n_ins->target = NULL; /* ease debugging */
531 iln->inline_start_instruction = n_ins;
536 static void emit_inlining_epilog(inline_node *iln,inline_node *callee,stackptr n_curstack,instruction *o_iptr)
540 assert(iln && callee && o_iptr);
541 assert(iln->inline_start_instruction);
543 n_ins = (iln->inlined_iinstr_cursor++);
544 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
546 n_ins->opc = ICMD_INLINE_END;
547 n_ins->method = callee->m;
548 n_ins->dst = n_curstack;
549 n_ins->line = o_iptr->line;
550 n_ins->target = iln->inline_start_instruction; /* needed for line number table creation */
553 static void rewrite_stack(inline_node *iln,stackptr o_first,stackptr o_last,ptrint curreloc)
563 DOLOG(printf("rewrite_stack: no stack slots\n"));
569 assert(o_first <= o_last);
571 n = o_last - o_first + 1;
575 n_sp = iln->n_inlined_stack_cursor;
578 printf("rewrite_stack: rewriting %d stack slots (%p,%p) -> (%d,%d)\n",
579 n,(void*)o_first,(void*)o_last,DEBUG_SLOT(n_sp),
580 DEBUG_SLOT(n_sp+n-1))
583 DOLOG( printf("o_first = "); debug_dump_stack(o_first); printf("\n") );
584 DOLOG( printf("o_last = "); debug_dump_stack(o_last); printf("\n") );
586 while (o_sp <= o_last) {
589 n_sp->prev = relocate_stack_ptr(iln,n_sp->prev,curreloc);
590 switch (n_sp->varkind) {
591 case STACKVAR: n_sp->varnum += iln->n_callerstackdepth; break;
592 case LOCALVAR: n_sp->varnum += iln->localsoffset; break;
598 DOLOG( printf("n_sp = "); debug_dump_stack(n_sp-1); printf("\n") );
600 iln->n_inlined_stack_cursor = n_sp;
603 static void inline_resolve_block_refs(inline_target_ref **refs,basicblock *o_bptr,basicblock *n_bptr)
605 inline_target_ref *ref;
606 inline_target_ref *prev;
611 if (*(ref->ref) == o_bptr) {
613 if ((ptrint) o_bptr < (0x333+100)) { /* XXX */
614 printf("resolving RETURN block reference %p -> new L%03d (%p)\n",
615 (void*)o_bptr,n_bptr->debug_nr,(void*)n_bptr);
618 printf("resolving block reference old L%03d (%p) -> new L%03d (%p)\n",
619 o_bptr->debug_nr,(void*)o_bptr,n_bptr->debug_nr,(void*)n_bptr);
623 *(ref->ref) = n_bptr;
625 prev->next = ref->next;
638 static basicblock * create_block(inline_node *iln,basicblock *o_bptr,inline_target_ref **refs,int indepth)
644 assert(iln && o_bptr && refs);
646 n_bptr = iln->inlined_basicblocks_cursor++;
649 memset(n_bptr,0,sizeof(basicblock));
652 n_bptr->type = BBTYPE_STD; /* XXX not necessary */
653 n_bptr->iinstr = iln->inlined_iinstr_cursor;
654 n_bptr->next = n_bptr+1;
655 n_bptr->debug_nr = iln->ctx->next_block_number++;
656 n_bptr->indepth = indepth;
659 /* allocate stackslots */
660 iln->n_inlined_stack_cursor += indepth;
661 n_sp = iln->n_inlined_stack_cursor - 1;
662 n_bptr->instack = n_sp;
664 /* link the stack elements */
665 for (i=indepth-1; i>=0; --i) {
666 n_sp->varkind = STACKVAR;
668 n_sp->prev = (i) ? n_sp-1 : NULL;
669 n_sp->flags = 0; /* XXX */
674 inline_resolve_block_refs(refs,o_bptr,n_bptr);
679 static void fill_translation_table(inline_node *iln,stackptr o_sp,stackptr n_sp,int n_depth)
684 printf("fill_translation_table (newdepth=%d):\n",n_depth);
685 printf("\tos_sp = "); debug_dump_stack(o_sp); printf("\n");
686 printf("\tns_sp = "); debug_dump_stack(n_sp); printf("\n");
689 /* we must translate all stack slots that were present before the call XXX */
690 /* and the instack of the block */
691 iln->ctx->stacktranslationstart = iln->ctx->stacktranslation + (n_depth - 1);
693 /* fill the translation table */
700 iln->ctx->stacktranslation[i].o_sp = o_sp;
701 iln->ctx->stacktranslation[i].n_sp = n_sp;
702 n_sp->flags |= (o_sp->flags & SAVEDVAR); /* XXX correct? */
703 n_sp->type = o_sp->type; /* XXX we overwrite this anyway with STACKVAR, right? */
711 assert(iln->ctx->stacktranslation[i].o_sp);
712 iln->ctx->stacktranslation[i].n_sp = n_sp;
713 n_sp->flags |= SAVEDVAR; /* XXX this is too conservative */
722 static void rewrite_method(inline_node *iln)
732 stackptr o_nexttorewrite;
733 stackptr o_lasttorewrite;
734 inline_node *nextcall;
737 inline_block_map *bm;
744 nextcall = iln->children;
746 /* set memory cursors */
747 iln->inlined_iinstr_cursor = iln->inlined_iinstr;
748 iln->n_inlined_stack_cursor = iln->n_inlined_stack;
749 iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
751 /* loop over basic blocks */
752 o_bptr = iln->m->basicblocks;
753 for (; o_bptr; o_bptr = o_bptr->next) {
755 if (o_bptr->flags < BBREACHED) {
757 printf("skipping old L%03d (flags=%d,type=%d,os=%p,oid=%d,ois=%p,cursor=%d,callerstack=%d) of ",
758 o_bptr->debug_nr,o_bptr->flags,o_bptr->type,
759 (void*)o_bptr->stack,o_bptr->indepth,(void*)o_bptr->instack,
760 DEBUG_SLOT(iln->n_inlined_stack_cursor),
761 DEBUG_SLOT(iln->n_callerstack));
762 method_println(iln->m);
765 n_bptr = create_block(iln,o_bptr,&(iln->refs),o_bptr->indepth + iln->n_callerstackdepth);
766 n_bptr->type = o_bptr->type;
767 /* enter it in the blockmap */
768 iln->ctx->blockmap[iln->ctx->blockmap_index].iln = iln;
769 iln->ctx->blockmap[iln->ctx->blockmap_index].o_block = o_bptr;
770 iln->ctx->blockmap[iln->ctx->blockmap_index++].n_block = n_bptr;
771 n_bptr->flags = o_bptr->flags;
775 assert(o_bptr->stack);
777 len = o_bptr->icount;
778 o_iptr = o_bptr->iinstr;
781 printf("rewriting old L%03d (flags=%d,type=%d,os=%p,oid=%d,ois=%p,cursor=%d,callerstack=%d) of ",
782 o_bptr->debug_nr,o_bptr->flags,o_bptr->type,
783 (void*)o_bptr->stack,o_bptr->indepth,(void*)o_bptr->instack,
784 DEBUG_SLOT(iln->n_inlined_stack_cursor),
785 DEBUG_SLOT(iln->n_callerstack));
786 method_println(iln->m);
787 printf("o_instack: ");debug_dump_stack(o_bptr->instack);printf("\n");
788 printf("o_callerstack: ");debug_dump_stack(iln->o_callerstack);printf("\n");
791 o_curstack = o_bptr->instack;
793 /* create an inlined clone of this block */
794 n_bptr = create_block(iln,o_bptr,&(iln->refs),o_bptr->indepth + iln->n_callerstackdepth);
795 n_bptr->type = o_bptr->type;
796 n_bptr->flags = o_bptr->flags;
798 /* enter it in the blockmap */
799 iln->ctx->blockmap[iln->ctx->blockmap_index].iln = iln;
800 iln->ctx->blockmap[iln->ctx->blockmap_index].o_block = o_bptr;
801 iln->ctx->blockmap[iln->ctx->blockmap_index++].n_block = n_bptr;
803 DOLOG( debug_dump_inline_context(iln) );
805 if (iln->n_callerstackdepth)
806 iln->n_callerstack = n_bptr->instack-o_bptr->indepth;
808 iln->n_callerstack = NULL;
809 fill_translation_table(iln,iln->o_callerstack,iln->n_callerstack,iln->n_callerstackdepth);
810 fill_translation_table(iln,o_bptr->instack,n_bptr->instack,n_bptr->indepth);
811 iln->ctx->o_translationlimit = o_bptr->stack;
813 DOLOG( debug_dump_inline_context(iln) );
815 /* calculate the stack element relocation */
816 curreloc = (u1*)iln->n_inlined_stack_cursor - (u1*)o_bptr->stack;
817 DOLOG( printf("curreloc <- %d = %p - %p\n",(int)curreloc,(void*)iln->n_inlined_stack_cursor,(void*)(u1*)o_bptr->stack) );
819 o_nexttorewrite = o_bptr->stack;
820 o_lasttorewrite = o_bptr->stack-1;
821 assert(o_nexttorewrite);
828 DOLOG( printf("o_curstack = "); debug_dump_stack(o_curstack); show_icmd(o_iptr,false); printf(", dst = "); debug_dump_stack(o_dst); printf("\n") );
830 if (nextcall && o_iptr == nextcall->callerins) {
832 /* rewrite stack elements produced so far in this block */
833 if (o_nexttorewrite <= o_lasttorewrite) {
834 rewrite_stack(iln, o_nexttorewrite, o_lasttorewrite, curreloc);
837 /* write the inlining prolog */
838 n_sp = emit_inlining_prolog(iln,nextcall,relocate_stack_ptr(iln,o_curstack,curreloc),o_iptr);
839 icount += nextcall->m->parseddesc->paramcount + 1; /* XXX prolog instructions */
841 /* find the first stack slot under the arguments of the invocation */
843 for (i=0; i < nextcall->m->parseddesc->paramcount; ++i) {
847 nextcall->o_callerstack = o_sp;
849 /* see how deep the new stack is after the arguments have been removed */
850 i = stack_depth(n_sp);
851 assert(i == stack_depth(nextcall->o_callerstack) + iln->n_callerstackdepth);
853 /* end current block */
854 n_bptr->icount = icount;
855 n_bptr->outstack = n_sp;
856 n_bptr->outdepth = i;
858 /* caller stack depth for the callee */
859 assert(nextcall->n_callerstackdepth == i);
861 /* set memory pointers in the callee */
862 nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
863 nextcall->n_inlined_stack = iln->n_inlined_stack_cursor;
864 nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
867 DOLOG( printf("entering inline "); show_icmd(o_iptr,false); printf("\n") );
868 rewrite_method(nextcall);
869 DOLOG( printf("leaving inline "); show_icmd(o_iptr,false); printf("\n") );
871 /* skip stack slots used by the inlined callee */
872 curreloc += (u1*)nextcall->n_inlined_stack_cursor - (u1*)iln->n_inlined_stack_cursor;
874 /* update memory cursors */
875 assert(nextcall->inlined_iinstr_cursor == iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
876 /*assert(nextcall->n_inlined_stack_cursor == iln->n_inlined_stack_cursor + nextcall->cumul_stackcount);*/
877 assert(nextcall->inlined_basicblocks_cursor == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
878 iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
879 iln->n_inlined_stack_cursor = nextcall->n_inlined_stack_cursor;
880 iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
882 /* start new block */
883 i = (nextcall->m->parseddesc->returntype.type == TYPE_VOID) ? 0 : 1; /* number of return slots */
884 assert(i == 0 || i == 1);
885 n_bptr = create_block(iln,(void*) (ptrint) (nextcall->depth + 0x333) /*XXX*/,
886 &(nextcall->refs),nextcall->n_callerstackdepth + i);
887 n_bptr->flags = o_bptr->flags;
890 /* skip allocated stack slots */
891 curreloc += sizeof(stackelement) * (n_bptr->indepth - i);
893 /* fill the translation table for the slots present before the call */
894 n_sp = n_bptr->instack;
895 fill_translation_table(iln,nextcall->o_callerstack,(i) ? n_sp->prev : n_sp,nextcall->n_callerstackdepth);
897 /* the return slot */
901 fill_translation_table(iln,o_dst,n_sp,nextcall->n_callerstackdepth + 1);
903 o_nexttorewrite = o_dst + 1;
904 o_lasttorewrite = o_dst;
907 /* the next chunk of stack slots start with (including) the slots produced */
908 /* by the invocation */
909 o_nexttorewrite = o_lasttorewrite + 1;
910 o_lasttorewrite = o_nexttorewrite - 1;
913 DOLOG( debug_dump_inline_context(iln) );
914 iln->ctx->o_translationlimit = o_nexttorewrite;
916 /* emit inlining epilog */
917 emit_inlining_epilog(iln,nextcall,n_sp,o_iptr);
918 icount++; /* XXX epilog instructions */
920 /* proceed to next call */
921 nextcall = nextcall->next;
924 printf("resuming old L%03d (flags=%d,type=%d,os=%p,oid=%d,ois=%p,cursor=%d,curreloc=%d,callerstack=%d) of ",
925 o_bptr->debug_nr,o_bptr->flags,o_bptr->type,
926 (void*)o_bptr->stack,o_bptr->indepth,(void*)o_bptr->instack,
927 DEBUG_SLOT(iln->n_inlined_stack_cursor),(int)curreloc,
928 DEBUG_SLOT(iln->n_callerstack));
929 method_println(iln->m);
933 emit_instruction(iln,o_iptr,curreloc,o_curstack);
936 if (o_dst > o_lasttorewrite)
937 o_lasttorewrite = o_dst;
940 DOLOG( printf("o_dst = %p\n",(void*)o_dst) );
945 /* end of basic block */
946 /* rewrite stack after last call */
947 if (o_nexttorewrite <= o_lasttorewrite) {
948 rewrite_stack(iln,o_nexttorewrite,o_lasttorewrite,curreloc);
950 n_bptr->outstack = relocate_stack_ptr(iln,o_bptr->outstack,curreloc);
951 n_bptr->outdepth = iln->n_callerstackdepth + o_bptr->outdepth;
952 assert(n_bptr->outdepth == stack_depth(n_bptr->outstack));
954 if (n_bptr->outstack) {
956 n_bptr->outstack += curreloc;
959 n_bptr->icount = icount;
961 n_iptr = iln->inlined_iinstr_cursor - 1;
962 if (n_iptr->opc == ICMD_INLINE_GOTO) {
963 DOLOG( printf("creating stack slot for ICMD_INLINE_GOTO\n") );
964 n_sp = iln->n_inlined_stack_cursor++;
966 *n_sp = *n_iptr->dst;
967 n_sp->prev = iln->n_callerstack;
970 n_bptr->outdepth = iln->n_callerstackdepth + 1;
971 n_bptr->outstack = n_sp;
975 /* end of basic blocks */
976 if (!iln->depth && n_bptr) {
980 bm = iln->ctx->blockmap;
981 for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
982 assert(bm->iln && bm->o_block && bm->n_block);
985 inline_resolve_block_refs(&(iln->refs),iln->ctx->blockmap[i].o_block,iln->ctx->blockmap[i].n_block);
990 inline_target_ref *ref;
993 if (!iln->depth || *(ref->ref) != (void*) (ptrint) (0x333 + iln->depth) /* XXX */) {
994 DOLOG( printf("XXX REMAINING REF at depth %d: %p\n",iln->depth,(void*)*(ref->ref)) );
1003 static basicblock * inline_map_block(inline_node *iln,basicblock *o_block,inline_node *targetiln)
1005 inline_block_map *bm;
1006 inline_block_map *bmend;
1014 bm = iln->ctx->blockmap;
1015 bmend = bm + iln->ctx->blockmap_index;
1017 while (bm < bmend) {
1018 assert(bm->iln && bm->o_block && bm->n_block);
1019 if (bm->o_block == o_block && bm->iln == targetiln)
1025 return NULL; /* not reached */
1028 static exceptiontable * inline_exception_tables(inline_node *iln,exceptiontable *n_extable,exceptiontable **prevextable)
1036 assert(prevextable);
1038 child = iln->children;
1041 n_extable = inline_exception_tables(child,n_extable,prevextable);
1042 child = child->next;
1043 } while (child != iln->children);
1046 et = iln->m->exceptiontable;
1047 for (i=0; i<iln->m->exceptiontablelength; ++i) {
1049 memset(n_extable,0,sizeof(exceptiontable));
1050 n_extable->startpc = et->startpc;
1051 n_extable->endpc = et->endpc;
1052 n_extable->handlerpc = et->handlerpc;
1053 n_extable->start = inline_map_block(iln,et->start,iln);
1054 n_extable->end = inline_map_block(iln,et->end,iln);
1055 n_extable->handler = inline_map_block(iln,et->handler,iln);
1056 n_extable->catchtype = et->catchtype;
1059 (*prevextable)->down = n_extable;
1061 *prevextable = n_extable;
1070 static void inline_locals(inline_node *iln,registerdata *rd)
1079 child = iln->children;
1082 inline_locals(child,rd);
1083 child = child->next;
1084 } while (child != iln->children);
1087 assert(iln->regdata);
1089 for (i=0; i<iln->m->maxlocals; ++i) {
1090 for (t=TYPE_INT; t<=TYPE_ADR; ++t) {
1091 DOLOG( printf("local %d type=%d in ",i,iln->regdata->locals[i][t].type); method_println(iln->m); );
1092 if (iln->regdata->locals[i][t].type >= 0) {
1093 rd->locals[iln->localsoffset + i][t].type = iln->regdata->locals[i][t].type;
1094 rd->locals[iln->localsoffset + i][t].flags |= iln->regdata->locals[i][t].flags;
1099 if (iln->regdata->memuse > rd->memuse)
1100 rd->memuse = iln->regdata->memuse;
1101 if (iln->regdata->argintreguse > rd->argintreguse)
1102 rd->argintreguse = iln->regdata->argintreguse;
1103 if (iln->regdata->argfltreguse > rd->argfltreguse)
1104 rd->argfltreguse = iln->regdata->argfltreguse;
1107 static void inline_stack_interfaces(inline_node *iln,registerdata *rd)
1116 assert(rd->interfaces);
1118 bptr = iln->inlined_basicblocks;
1119 for (i=0; i<iln->cumul_basicblockcount; ++i, ++bptr) {
1120 DOLOG( printf("INLINE STACK INTERFACE block L%03d\n",bptr->debug_nr) );
1121 DOLOG( printf("\toutstack = ");debug_dump_stack(bptr->outstack);printf("\n") );
1122 DOLOG( printf("\tinstack = ");debug_dump_stack(bptr->outstack);printf("\n") );
1124 assert(bptr->outdepth == stack_depth(bptr->outstack));
1125 assert(bptr->indepth == stack_depth(bptr->instack));
1127 sp = bptr->outstack;
1128 d = bptr->outdepth - 1;
1130 if ((sp->varkind == STACKVAR) && (sp->varnum > d)) {
1131 sp->varkind = TEMPVAR;
1134 sp->varkind = STACKVAR;
1137 DOLOG( printf("INLINE STACK INTERFACE L%03d outstack d=%d varkind=%d varnum=%d type=%d flags=%01x\n",
1138 bptr->debug_nr,d,sp->varkind,sp->varnum,sp->type,sp->flags) );
1139 rd->interfaces[d][sp->type].type = sp->type;
1140 rd->interfaces[d][sp->type].flags |= sp->flags;
1146 d = bptr->indepth - 1;
1148 rd->interfaces[d][sp->type].type = sp->type;
1149 if (sp->varkind == STACKVAR && (sp->flags & SAVEDVAR)) {
1150 rd->interfaces[d][sp->type].flags |= SAVEDVAR;
1152 DOLOG( printf("INLINE STACK INTERFACE L%03d instack d=%d varkind=%d varnum=%d type=%d flags=%01x\n",
1153 bptr->debug_nr,d,sp->varkind,sp->varnum,sp->type,sp->flags) );
1160 static bool inline_inline_intern(methodinfo *m, codegendata *cd, registerdata *rd, inline_node *iln)
1166 stackptr o_curstack;
1167 int opcode; /* invocation opcode */
1169 inline_node *calleenode;
1170 inline_node *active;
1177 iln->cumul_maxstack = iln->n_callerstackdepth + m->maxstack + 1 /* XXX builtins */;
1178 iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
1179 iln->cumul_exceptiontablelength += m->exceptiontablelength;
1181 bptr = m->basicblocks;
1182 for (; bptr; bptr = bptr->next) {
1184 iln->cumul_basicblockcount++;
1186 if (bptr->flags < BBREACHED)
1189 assert(bptr->stack);
1192 iptr = bptr->iinstr;
1193 o_curstack = bptr->instack;
1195 iln->instructioncount += len;
1196 iln->cumul_instructioncount += len;
1199 printf("ADD INSTRUCTIONS [%d]: %d, count=%d, cumulcount=%d\n",
1200 iln->depth,len,iln->instructioncount,iln->cumul_instructioncount);
1203 while (--len >= 0) {
1210 /* XXX we cannot deal with IINC's stack hacking */
1213 case ICMD_LOOKUPSWITCH:
1214 case ICMD_TABLESWITCH:
1215 /* XXX these are not implemented, yet. */
1218 /****************************************/
1221 case ICMD_INVOKEVIRTUAL:
1222 case ICMD_INVOKESPECIAL:
1223 case ICMD_INVOKESTATIC:
1224 case ICMD_INVOKEINTERFACE:
1225 callee = (methodinfo *) iptr[0].val.a;
1228 if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE) || opcode == ICMD_INVOKESPECIAL)
1229 && !(callee->flags & (ACC_NATIVE | ACC_SYNCHRONIZED)))
1231 if (iln->depth < 3) {
1232 for (active = iln; active; active = active->parent) {
1233 if (callee == active->m) {
1234 DOLOG( printf("RECURSIVE!\n") );
1239 calleenode = DNEW(inline_node);
1240 memset(calleenode,0,sizeof(inline_node));
1242 calleenode->ctx = iln->ctx;
1243 calleenode->m = callee;
1245 if (!inline_jit_compile(calleenode))
1248 calleenode->depth = iln->depth+1;
1249 calleenode->callerblock = bptr;
1250 calleenode->callerins = iptr;
1251 calleenode->callerpc = iptr - m->basicblocks->iinstr;
1253 calleenode->localsoffset = iln->localsoffset + m->maxlocals;
1254 calleenode->prolog_instructioncount = callee->parseddesc->paramcount;
1256 calleenode->stackcount = callee->stackcount;
1257 calleenode->cumul_stackcount = callee->stackcount;
1259 /* see how deep the stack is below the arguments */
1261 for (i=0; sp; sp = sp->prev)
1263 calleenode->n_callerstackdepth = iln->n_callerstackdepth + i - callee->parseddesc->paramcount;
1265 insert_inline_node(iln,calleenode);
1267 if (!inline_inline_intern(callee,cd,rd,calleenode))
1270 iln->cumul_instructioncount += calleenode->prolog_instructioncount;
1271 iln->cumul_instructioncount += calleenode->cumul_instructioncount - 1/*invoke*/ + 2 /*INLINE_START|END*/;
1272 iln->cumul_stackcount += calleenode->cumul_stackcount;
1273 iln->cumul_basicblockcount += calleenode->cumul_basicblockcount + 1/*XXX*/;
1274 iln->cumul_exceptiontablelength += calleenode->cumul_exceptiontablelength;
1275 if (calleenode->cumul_maxstack > iln->cumul_maxstack)
1276 iln->cumul_maxstack = calleenode->cumul_maxstack;
1277 if (calleenode->cumul_maxlocals > iln->cumul_maxlocals)
1278 iln->cumul_maxlocals = calleenode->cumul_maxlocals;
1291 /* end of basic block */
1297 static bool test_inlining(inline_node *iln,codegendata *cd,registerdata *rd,
1298 methodinfo **resultmethod, codegendata **resultcd, registerdata **resultrd)
1303 methodinfo *n_method;
1304 exceptiontable *n_ext;
1305 exceptiontable *prevext;
1309 static int debug_verify_inlined_code = 1;
1310 static int debug_compile_inlined_code_counter = 0;
1312 assert(iln && cd && rd && resultmethod && resultcd && resultrd);
1314 *resultmethod = iln->m;
1319 if (debug_compile_inlined_code_counter >5)
1323 n_ins = DMNEW(instruction,iln->cumul_instructioncount);
1324 iln->inlined_iinstr = n_ins;
1326 n_stack = DMNEW(stackelement,iln->cumul_stackcount + 1000 /* XXX */);
1327 iln->n_inlined_stack = n_stack;
1328 iln->ctx->n_debug_stackbase = n_stack;
1330 n_bb = DMNEW(basicblock,iln->cumul_basicblockcount);
1331 iln->inlined_basicblocks = n_bb;
1333 iln->ctx->blockmap = DMNEW(inline_block_map,iln->cumul_basicblockcount);
1335 rewrite_method(iln);
1337 if (iln->cumul_exceptiontablelength) {
1338 n_ext = DMNEW(exceptiontable,iln->cumul_exceptiontablelength);
1340 inline_exception_tables(iln,n_ext,&prevext);
1342 prevext->down = NULL;
1348 /*******************************************************************************/
1350 n_method = NEW(methodinfo);
1351 memcpy(n_method,iln->m,sizeof(methodinfo));
1352 n_method->maxstack = iln->cumul_maxstack; /* XXX put into cd,rd */
1353 n_method->maxlocals = iln->cumul_maxlocals;
1354 n_method->basicblockcount = iln->cumul_basicblockcount;
1355 n_method->basicblocks = iln->inlined_basicblocks;
1356 n_method->basicblockindex = NULL;
1357 n_method->instructioncount = iln->cumul_instructioncount;
1358 n_method->instructions = iln->inlined_iinstr;
1359 n_method->stackcount = iln->cumul_stackcount + 1000 /* XXX */;
1360 n_method->stack = iln->n_inlined_stack;
1362 n_method->exceptiontablelength = iln->cumul_exceptiontablelength;
1363 n_method->exceptiontable = n_ext;
1364 n_method->linenumbercount = 0;
1366 n_cd = DNEW(codegendata);
1367 memcpy(n_cd,cd,sizeof(codegendata));
1368 n_cd->method = n_method;
1369 n_cd->maxstack = n_method->maxstack;
1370 n_cd->maxlocals = n_method->maxlocals;
1371 n_cd->exceptiontablelength = n_method->exceptiontablelength;
1372 n_cd->exceptiontable = n_method->exceptiontable;
1374 n_rd = DNEW(registerdata);
1375 reg_setup(n_method, n_rd);
1378 inline_locals(iln,n_rd);
1379 DOLOG( printf("INLINING STACK INTERFACES FOR "); method_println(iln->m) );
1380 inline_stack_interfaces(iln,n_rd);
1382 if (debug_verify_inlined_code) {
1383 debug_verify_inlined_code = 0;
1384 DOLOG( printf("VERIFYING INLINED RESULT...\n") );
1385 if (!typecheck(n_method,n_cd,n_rd)) {
1386 *exceptionptr = NULL;
1387 DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
1391 DOLOG( printf("VERIFICATION PASSED.\n") );
1393 debug_verify_inlined_code = 1;
1397 if (n_method->instructioncount >= inline_debug_min_size && n_method->instructioncount <= inline_debug_max_size) {
1398 if (debug_compile_inlined_code_counter >= inline_debug_start_counter
1399 && debug_compile_inlined_code_counter <= inline_debug_end_counter)
1402 (strcmp(n_method->class->name->text,"java/lang/reflect/Array") == 0 &&
1403 strcmp(n_method->name->text,"<clinit>") == 0 &&
1404 strcmp(n_method->descriptor->text,"()V") == 0)
1406 (strcmp(n_method->class->name->text,"java/lang/VMClassLoader") == 0 &&
1407 strcmp(n_method->name->text,"getSystemClassLoader") == 0 &&
1408 strcmp(n_method->descriptor->text,"()Ljava/lang/ClassLoader;") == 0)
1414 *resultmethod = n_method;
1417 inline_count_methods++;
1418 if (inline_debug_log_names)
1419 method_println(n_method);
1422 printf("==== %d.INLINE ==================================================================\n",debug_compile_inlined_code_counter);
1423 method_println(n_method);
1424 show_icmd_method(iln->m,cd,rd);
1425 dump_inline_tree(iln);
1426 show_icmd_method(n_method,n_cd,n_rd);
1427 debug_dump_inlined_code(iln,n_method,n_cd,n_rd);
1428 printf("-------- DONE -----------------------------------------------------------\n");
1433 debug_compile_inlined_code_counter++;
1438 bool inline_inline(methodinfo *m, codegendata *cd, registerdata *rd,
1439 methodinfo **resultmethod, codegendata **resultcd, registerdata **resultrd)
1444 printf("==== INLINE ==================================================================\n");
1448 iln = DNEW(inline_node);
1449 memset(iln,0,sizeof(inline_node));
1451 iln->ctx = (inline_context *) DMNEW(u1,sizeof(inline_context) + sizeof(inline_stack_translation) * 1000 /* XXX */);
1452 memset(iln->ctx,0,sizeof(inline_context));
1453 iln->ctx->stacktranslationstart = iln->ctx->stacktranslation - 1;
1456 /* we cannot use m->instructioncount because it may be greater than
1457 * the actual number of instructions in the basic blocks. */
1458 iln->instructioncount = 0;
1459 iln->cumul_instructioncount = 0;
1461 iln->stackcount = m->stackcount;
1462 iln->cumul_stackcount = m->stackcount;
1464 if (inline_inline_intern(m,cd,rd,iln)) {
1467 printf("==== TEST INLINE =============================================================\n");
1472 test_inlining(iln,cd,rd,resultmethod,resultcd,resultrd);
1476 printf("-------- DONE -----------------------------------------------------------\n");
1484 * These are local overrides for various environment variables in Emacs.
1485 * Please do not remove this and leave it at the end of the file, where
1486 * Emacs will automagically detect them.
1487 * ---------------------------------------------------------------------
1490 * indent-tabs-mode: t
1494 * vim:noexpandtab:sw=4:ts=4: