1 /* src/vm/jit/inline/inline.c - method inlining
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 5960 2006-11-12 13:38:34Z edwin $
44 #include "mm/memory.h"
45 #include "toolbox/logging.h"
46 #include "vm/builtin.h"
47 #include "vm/global.h"
48 #include "vm/options.h"
49 #include "vm/statistics.h"
50 #include "vm/jit/jit.h"
51 #include "vm/jit/parse.h"
52 #include "vm/jit/inline/inline.h"
53 #include "vm/jit/loop/loop.h"
56 #include "vm/initialize.h"
57 #include "vm/method.h"
58 #include "vm/jit/jit.h"
59 #include "vm/jit/show.h"
61 #include "vm/jit/reg.h"
62 #include "vm/jit/stack.h"
64 #include "vm/jit/verify/typecheck.h"
66 #if defined(ENABLE_THREADS)
67 # include "threads/native/threads.h"
71 /* debugging ******************************************************************/
74 #define INLINE_VERBOSE
75 bool inline_debug_log = 0;
76 bool inline_debug_log_names = 0;
77 int inline_debug_start_counter = 0;
78 int inline_debug_max_size = INT_MAX;
79 int inline_debug_min_size = 0;
80 int inline_debug_end_counter = INT_MAX;
81 int inline_count_methods = 0;
82 #define DOLOG(code) do{ if (inline_debug_log) { code; } }while(0)
88 /* types **********************************************************************/
90 typedef struct inline_node inline_node;
91 typedef struct inline_target_ref inline_target_ref;
92 typedef struct inline_context inline_context;
93 typedef struct inline_block_map inline_block_map;
100 inline_node *children;
101 inline_node *next; /* next node at this depth */
102 inline_node *prev; /* prev node at this depth */
103 int depth; /* inlining depth, 0 for root */
105 /* info about the call site (if depth > 0)*/
106 inline_node *parent; /* node of the caller (NULL for root) */
107 basicblock *callerblock; /* original block containing the INVOKE* */
108 instruction *callerins; /* the original INVOKE* instruction */
110 s4 *n_passthroughvars;
111 int n_passthroughcount;
112 int n_selfpassthroughcount; /* # of pass-through vars of the call itself */
113 exception_entry **o_handlers;
114 int n_handlercount; /* # of handlers protecting this call */
116 int synclocal; /* variable used for synchr., or UNUSED */
118 bool blockbefore; /* block boundary before inlined body? */
119 bool blockafter; /* block boundary after inlined body? */
121 /* info about the callee */
123 int prolog_instructioncount; /* # of ICMDs in the inlining prolog */
124 int epilog_instructioncount; /* # of ICMDs in the inlining epilog */
125 int extra_instructioncount;
126 int instructioncount;
127 bool synchronize; /* do we have to synchronize enter/exit? */
128 basicblock *handler_monitorexit; /* handler for synchronized inlinees */
131 /* cumulative values */
132 int cumul_instructioncount; /* ICMDs in this node and its children */
133 int cumul_basicblockcount; /* BBs started by this node and its children */
134 int cumul_blockmapcount;
136 int cumul_exceptiontablelength;
139 instruction *inlined_iinstr;
140 instruction *inlined_iinstr_cursor;
141 basicblock *inlined_basicblocks;
142 basicblock *inlined_basicblocks_cursor;
145 registerdata *regdata;
148 inline_target_ref *refs;
149 instruction *inline_start_instruction;
157 struct inline_target_ref {
158 inline_target_ref *next;
163 struct inline_block_map {
169 struct inline_context {
174 int next_block_number;
175 inline_block_map *blockmap;
182 int next_debugnr; /* XXX debug */
186 /* prototypes *****************************************************************/
188 static bool inline_inline_intern(methodinfo *m, inline_node *iln);
189 static void inline_post_process(jitdata *jd);
192 /* debug helpers **************************************************************/
195 #include "inline_debug.inc"
197 void inline_print_stats()
199 printf("inlined callers: %d\n", inline_count_methods);
204 /* compilation of callees *****************************************************/
206 static bool inline_jit_compile_intern(jitdata *jd)
210 /* XXX should share code with jit.c */
214 /* XXX initialize the static function's class */
218 /* call the compiler passes ***********************************************/
220 /* call parse pass */
222 DOLOG( log_message_class("Parsing ", m->class) );
227 /* call stack analysis pass */
229 if (!stack_analyse(jd)) {
237 static bool inline_jit_compile(inline_node *iln)
243 /* XXX should share code with jit.c */
249 #if defined(ENABLE_THREADS)
250 /* enter a monitor on the method */
251 lock_monitor_enter((java_objectheader *) m);
254 /* allocate jitdata structure and fill it */
256 jd = jit_jitdata_new(m);
259 jd->flags = 0; /* XXX */
261 /* initialize the register allocator */
265 /* setup the codegendata memory */
267 /* XXX do a pseudo setup */
268 jd->cd = DNEW(codegendata);
269 MZERO(jd->cd, codegendata, 1);
270 jd->cd->maxstack = m->maxstack;
272 /* XXX uses too much dump memory codegen_setup(jd); */
274 /* now call internal compile function */
276 r = inline_jit_compile_intern(jd);
279 iln->regdata = jd->rd;
282 /* free some memory */
285 #if defined(ENABLE_JIT)
286 # if defined(ENABLE_INTRP)
294 #if defined(ENABLE_THREADS)
295 /* leave the monitor */
296 lock_monitor_exit((java_objectheader *) m );
303 /* inlining tree handling *****************************************************/
305 static void insert_inline_node(inline_node *parent, inline_node *child)
310 assert(parent && child);
312 child->parent = parent;
314 child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
316 first = parent->children;
318 /* insert as only node */
319 parent->children = child;
325 /* {there is at least one child already there} */
327 /* XXX is this search necessary, or could we always add at the end? */
330 while (succ->callerpc < child->callerpc) {
333 /* insert as last node */
334 child->prev = first->prev;
336 child->prev->next = child;
337 child->next->prev = child;
342 assert(succ->callerpc > child->callerpc);
344 /* insert before succ */
346 child->prev = succ->prev;
348 child->prev->next = child;
349 child->next->prev = child;
353 /* variable handling **********************************************************/
355 static s4 inline_new_variable(jitdata *jd, s4 type, s4 flags)
360 index = jd->vartop++;
361 if (index >= jd->varcount) {
362 newcount = jd->vartop * 2; /* XXX */
363 jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, newcount);
364 MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
365 jd->varcount = newcount;
368 jd->var[index].type = type;
369 jd->var[index].flags = flags;
375 static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
380 v = &(origjd->var[origidx]);
382 newidx = inline_new_variable(jd, v->type, v->flags);
384 jd->var[newidx].vv = v->vv;
390 static s4 inline_new_temp_variable(jitdata *jd, s4 type)
392 return inline_new_variable(jd, type, 0);
396 static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
403 idx = inline_new_variable_clone(jd, origjd, index);
411 static s4 *create_variable_map(inline_node *callee)
420 /* create the variable mapping */
422 varmap = DMNEW(s4, callee->jd->varcount);
423 for (i=0; i<callee->jd->varcount; ++i)
426 /* translate local variables */
428 for (i=0; i<callee->m->maxlocals; ++i) {
429 for (t=0; t<5; ++t) {
430 idx = callee->jd->local_map[5*i + t];
434 v = &(callee->jd->var[idx]);
435 assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
436 v->type = t; /* XXX restore if it is TYPE_VOID */
438 avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
440 if (avail == UNUSED) {
441 avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, idx);
442 callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
449 /* for synchronized instance methods we need an extra local */
451 if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
452 n_idx = callee->localsoffset - 1;
454 assert(callee->parent);
455 assert(n_idx == callee->parent->localsoffset + callee->parent->m->maxlocals);
457 avail = callee->ctx->resultjd->local_map[5*n_idx + TYPE_ADR];
459 if (avail == UNUSED) {
460 avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
461 callee->ctx->resultjd->local_map[5*n_idx + TYPE_ADR] = avail;
464 callee->synclocal = avail;
467 callee->synclocal = UNUSED;
474 /* basic block translation ****************************************************/
476 #define INLINE_RETURN_REFERENCE(callee) \
477 ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
480 static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
482 inline_target_ref *ref;
484 ref = DNEW(inline_target_ref);
486 ref->next = iln->refs;
491 static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
496 assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
498 ctx->blockmap[ctx->blockmap_index].iln = iln;
499 ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
500 ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
502 ctx->blockmap_index++;
506 static basicblock * inline_map_block(inline_node *iln,
508 inline_node *targetiln)
510 inline_block_map *bm;
511 inline_block_map *bmend;
519 bm = iln->ctx->blockmap;
520 bmend = bm + iln->ctx->blockmap_index;
523 assert(bm->iln && bm->o_block && bm->n_block);
524 if (bm->o_block == o_block && bm->iln == targetiln)
530 return NULL; /* not reached */
534 static void inline_resolve_block_refs(inline_target_ref **refs,
538 inline_target_ref *ref;
539 inline_target_ref *prev;
544 if (*(ref->ref) == o_bptr) {
546 #if defined(INLINE_VERBOSE)
547 if (inline_debug_log) {
548 if ((ptrint) o_bptr < (0x333+100)) { /* XXX */
549 printf("resolving RETURN block reference %p -> new L%03d (%p)\n",
550 (void*)o_bptr, n_bptr->nr, (void*)n_bptr);
553 printf("resolving block reference old L%03d (%p) -> new L%03d (%p)\n",
554 o_bptr->nr, (void*)o_bptr, n_bptr->nr, (void*)n_bptr);
559 *(ref->ref) = n_bptr;
561 prev->next = ref->next;
575 /* basic block creation *******************************************************/
577 static basicblock * create_block(inline_node *container,
581 inline_target_ref **refs,
594 assert(indepth >= 0);
596 n_bptr = container->inlined_basicblocks_cursor++;
598 assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
600 BASICBLOCK_INIT(n_bptr, iln->m);
602 n_bptr->iinstr = container->inlined_iinstr_cursor;
603 n_bptr->next = n_bptr + 1;
604 n_bptr->nr = container->ctx->next_block_number++;
605 n_bptr->indepth = indepth;
606 n_bptr->flags = BBFINISHED; /* XXX */
608 /* set the inlineinfo of the new block */
610 if (iln->inline_start_instruction)
611 n_bptr->inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
613 if (indepth > container->ctx->maxinoutdepth)
614 container->ctx->maxinoutdepth = indepth;
617 n_bptr->invars = DMNEW(s4, indepth);
620 for (i=0; i<indepth; ++i)
621 n_bptr->invars[i] = -1; /* XXX debug */
623 /* pass-through variables enter the block */
625 outer = inner->parent;
626 while (outer != NULL) {
627 depth = outer->n_passthroughcount;
629 assert(depth + inner->n_selfpassthroughcount <= indepth);
631 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
632 varidx = inner->n_passthroughvars[i];
634 inline_new_variable_clone(container->ctx->resultjd,
637 n_bptr->invars[depth + i] = newvaridx;
638 outer->varmap[varidx] = newvaridx;
641 outer = outer->parent;
645 n_bptr->invars = NULL;
648 /* XXX move this to callers with o_bptr != NULL? */
651 inline_resolve_block_refs(refs, o_bptr, n_bptr);
654 /* XXX for the verifier. should not be here */
659 dv = DMNEW(varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
660 MZERO(dv, varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
661 n_bptr->inlocals = dv;
668 static s4 *translate_javalocals(inline_node *iln, s4 *javalocals)
673 jl = DMNEW(s4, iln->jd->maxlocals);
675 for (i=0; i<iln->jd->maxlocals; ++i) {
678 j = inline_translate_variable(iln->ctx->resultjd, iln->jd, iln->varmap, j);
686 static basicblock * create_body_block(inline_node *iln,
687 basicblock *o_bptr, s4 *varmap)
692 n_bptr = create_block(iln, iln, iln, o_bptr, &(iln->refs),
693 o_bptr->indepth + iln->n_passthroughcount);
695 n_bptr->type = o_bptr->type;
696 n_bptr->flags = o_bptr->flags;
698 /* translate the invars of the original block */
700 for (i=0; i<o_bptr->indepth; ++i) {
701 n_bptr->invars[iln->n_passthroughcount + i] =
702 inline_translate_variable(iln->ctx->resultjd, iln->jd,
707 /* translate javalocals info */
709 n_bptr->javalocals = translate_javalocals(iln, o_bptr->javalocals);
715 static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
721 /* number of return variables */
723 retcount = (callee->n_resultlocal == -1
724 && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
726 /* start the epilog block */
728 n_bptr = create_block(caller, caller, callee, INLINE_RETURN_REFERENCE(callee),
729 &(callee->refs), callee->n_passthroughcount + retcount);
731 /* return variable */
734 idx = inline_new_variable(caller->ctx->resultjd,
735 callee->m->parseddesc->returntype.type, 0 /* XXX */);
736 n_bptr->invars[callee->n_passthroughcount] = idx;
737 varmap[callee->callerins->dst.varindex] = idx;
742 n_bptr->javalocals = DMNEW(s4, caller->jd->maxlocals);
743 MCOPY(n_bptr->javalocals, caller->javalocals, s4, caller->jd->maxlocals);
745 /* set block flags & type */
747 n_bptr->flags = /* XXX original block flags */ BBFINISHED;
748 n_bptr->type = BBTYPE_STD;
754 static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
761 n_bptr->outdepth = outdepth;
762 n_bptr->outvars = DMNEW(s4, outdepth);
764 for (i=0; i<outdepth; ++i)
765 n_bptr->outvars[i] = 0; /* XXX debug */
767 if (outdepth > iln->ctx->maxinoutdepth)
768 iln->ctx->maxinoutdepth = outdepth;
770 /* pass-through variables leave the block */
772 outer = inner->parent;
773 while (outer != NULL) {
774 depth = outer->n_passthroughcount;
776 assert(depth + inner->n_selfpassthroughcount <= outdepth);
778 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
779 varidx = inner->n_passthroughvars[i];
780 n_bptr->outvars[depth + i] =
781 inline_translate_variable(iln->ctx->resultjd,
787 outer = outer->parent;
792 static void close_prolog_block(inline_node *iln,
794 inline_node *nextcall)
796 /* XXX add original outvars! */
797 close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
799 /* pass-through variables */
801 DOLOG( printf("closed prolog block:\n");
802 show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
806 static void close_body_block(inline_node *iln,
815 close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
817 /* translate the outvars of the original block */
820 for (i=0; i<o_bptr->outdepth; ++i) {
821 n_bptr->outvars[iln->n_passthroughcount + i] =
822 inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
826 /* set the return variable, if any */
830 n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
835 /* inlined code generation ****************************************************/
837 static s4 emit_inlining_prolog(inline_node *iln,
849 insinfo_inline *insinfo;
852 assert(iln && callee && o_iptr);
855 md = calleem->parseddesc;
856 isstatic = (calleem->flags & ACC_STATIC);
858 localindex = callee->localsoffset + md->paramslots;
860 for (i=md->paramcount-1; i>=0; --i) {
863 n_ins = (iln->inlined_iinstr_cursor++);
864 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
866 type = md->paramtypes[i].type;
868 localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
869 assert(callee->regdata);
871 /* translate the argument variable */
873 argvar = varmap[o_iptr->sx.s23.s2.args[i]];
874 assert(argvar != UNUSED);
876 /* remove preallocation from the argument variable */
878 iln->ctx->resultjd->var[argvar].flags &= ~(PREALLOC | INMEMORY);
880 /* check the instance slot against NULL */
882 if (!isstatic && i == 0) {
883 assert(type == TYPE_ADR);
884 n_ins->opc = ICMD_CHECKNULL;
885 n_ins->s1.varindex = argvar;
886 n_ins->dst.varindex = n_ins->s1.varindex;
887 n_ins->line = o_iptr->line;
889 n_ins = (iln->inlined_iinstr_cursor++);
890 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
893 /* store argument into local variable of inlined callee */
895 if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != UNUSED)
897 /* this value is used in the callee */
899 if (i == 0 && callee->synclocal != UNUSED) {
900 /* we also need it for synchronization, so copy it */
901 assert(type == TYPE_ADR);
902 n_ins->opc = ICMD_COPY;
905 n_ins->opc = ICMD_ISTORE + type;
906 n_ins->sx.s23.s3.javaindex = UNUSED;
908 n_ins->s1.varindex = argvar;
909 n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
910 assert(n_ins->dst.varindex != UNUSED);
912 else if (i == 0 && callee->synclocal != UNUSED) {
913 /* the value is not used inside the callee, but we need it for */
914 /* synchronization */
915 /* XXX In this case it actually makes no sense to create a */
916 /* separate synchronization variable. */
918 n_ins->opc = ICMD_NOP;
921 /* this value is not used, pop it */
923 n_ins->opc = ICMD_POP;
924 n_ins->s1.varindex = argvar;
926 n_ins->line = o_iptr->line;
928 DOLOG( printf("%sprolog: ", iln->indent);
929 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
932 /* ASTORE for synchronized instance methods */
934 if (callee->synclocal != UNUSED) {
935 n_ins = (iln->inlined_iinstr_cursor++);
936 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
938 n_ins->opc = ICMD_ASTORE;
939 n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
940 n_ins->dst.varindex = callee->synclocal;
941 n_ins->sx.s23.s3.javaindex = UNUSED;
942 n_ins->line = o_iptr->line;
944 assert(n_ins->s1.varindex != UNUSED);
947 /* INLINE_START instruction */
949 n_ins = (iln->inlined_iinstr_cursor++);
950 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
952 insinfo = DNEW(insinfo_inline);
953 insinfo->method = callee->m;
954 insinfo->outer = iln->m;
955 insinfo->synclocal = callee->synclocal;
956 insinfo->synchronize = callee->synchronize;
957 insinfo->javalocals_start = NULL;
958 insinfo->javalocals_end = NULL;
960 /* info about stack vars live at the INLINE_START */
962 insinfo->throughcount = callee->n_passthroughcount;
963 insinfo->stackvarscount = o_iptr->s1.argcount - md->paramcount;
964 insinfo->stackvars = DMNEW(s4, insinfo->stackvarscount);
965 for (i=0; i<insinfo->stackvarscount; ++i)
966 insinfo->stackvars[i] = iln->varmap[o_iptr->sx.s23.s2.args[md->paramcount + i]];
968 /* info about the surrounding inlining */
970 if (iln->inline_start_instruction)
971 insinfo->parent = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
973 insinfo->parent = NULL;
975 /* finish the INLINE_START instruction */
977 n_ins->opc = ICMD_INLINE_START;
978 n_ins->sx.s23.s3.inlineinfo = insinfo;
979 n_ins->line = o_iptr->line;
980 n_ins->flags.bits = o_iptr->flags.bits & INS_FLAG_ID_MASK;
981 callee->inline_start_instruction = n_ins;
983 DOLOG( printf("%sprolog: ", iln->indent);
984 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
990 static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
995 assert(iln && callee && o_iptr);
996 assert(callee->inline_start_instruction);
998 /* INLINE_END instruction */
1000 n_ins = (iln->inlined_iinstr_cursor++);
1001 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
1003 n_ins->opc = ICMD_INLINE_END;
1004 n_ins->sx.s23.s3.inlineinfo = callee->inline_start_instruction->sx.s23.s3.inlineinfo;
1005 n_ins->line = o_iptr->line;
1007 /* set the javalocals */
1009 jl = DMNEW(s4, iln->jd->maxlocals);
1010 MCOPY(jl, iln->javalocals, s4, iln->jd->maxlocals);
1011 n_ins->sx.s23.s3.inlineinfo->javalocals_end = jl;
1013 DOLOG( printf("%sepilog: ", iln->indent);
1014 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1018 #define TRANSLATE_VAROP(vo) \
1019 n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
1022 static void inline_clone_instruction(inline_node *iln,
1026 instruction *o_iptr,
1027 instruction *n_iptr)
1029 icmdtable_entry_t *icmdt;
1030 builtintable_entry *bte;
1033 branch_target_t *table;
1034 lookup_target_t *lookup;
1039 icmdt = &(icmd_table[o_iptr->opc]);
1041 switch (icmdt->dataflow) {
1046 TRANSLATE_VAROP(sx.s23.s3);
1048 TRANSLATE_VAROP(sx.s23.s2);
1050 TRANSLATE_VAROP(s1);
1054 TRANSLATE_VAROP(sx.s23.s2);
1058 TRANSLATE_VAROP(s1);
1060 TRANSLATE_VAROP(dst);
1064 n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1065 for (i=0; i<n_iptr->s1.argcount; ++i) {
1066 n_iptr->sx.s23.s2.args[i] =
1067 inline_translate_variable(jd, origjd, varmap,
1068 o_iptr->sx.s23.s2.args[i]);
1070 TRANSLATE_VAROP(dst);
1074 INSTRUCTION_GET_METHODDESC(n_iptr, md);
1076 n_iptr->s1.argcount += iln->n_passthroughcount;
1077 n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1078 for (i=0; i<o_iptr->s1.argcount; ++i) {
1079 n_iptr->sx.s23.s2.args[i] =
1080 inline_translate_variable(jd, origjd, varmap,
1081 o_iptr->sx.s23.s2.args[i]);
1083 for (scope = iln; scope != NULL; scope = scope->parent) {
1084 for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
1085 n_iptr->sx.s23.s2.args[i++] =
1086 scope->parent->varmap[scope->n_passthroughvars[j]];
1089 if (md->returntype.type != TYPE_VOID)
1090 TRANSLATE_VAROP(dst);
1094 bte = n_iptr->sx.s23.s3.bte;
1102 switch (icmdt->controlflow) {
1104 TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
1108 inline_add_block_reference(iln, &(n_iptr->dst.block));
1112 inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
1116 i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
1118 table = DMNEW(branch_target_t, i);
1119 MCOPY(table, o_iptr->dst.table, branch_target_t, i);
1120 n_iptr->dst.table = table;
1123 inline_add_block_reference(iln, &(table->block));
1129 inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
1131 i = n_iptr->sx.s23.s2.lookupcount;
1132 lookup = DMNEW(lookup_target_t, i);
1133 MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
1134 n_iptr->dst.lookup = lookup;
1137 inline_add_block_reference(iln, &(lookup->target.block));
1143 /* XXX move this to dataflow section? */
1145 switch (n_iptr->opc) {
1151 /* XXX share code with stack.c */
1152 j = n_iptr->dst.varindex;
1153 i = n_iptr->sx.s23.s3.javaindex;
1155 if (n_iptr->flags.bits & INS_FLAG_RETADDR)
1156 iln->javalocals[i] = UNUSED;
1158 iln->javalocals[i] = j;
1159 if (n_iptr->flags.bits & INS_FLAG_KILL_PREV)
1160 iln->javalocals[i-1] = UNUSED;
1161 if (n_iptr->flags.bits & INS_FLAG_KILL_NEXT)
1162 iln->javalocals[i+1] = UNUSED;
1169 static void rewrite_method(inline_node *iln)
1173 instruction *o_iptr;
1174 instruction *n_iptr;
1175 inline_node *nextcall;
1177 inline_block_map *bm;
1182 char indent[100]; /* XXX debug */
1188 resultjd = iln->ctx->resultjd;
1192 nextcall = iln->children;
1195 for (i=0; i<iln->depth; ++i)
1198 iln->indent = indent;
1200 DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
1201 printf("%s(passthrough: %d+%d)\n",
1202 indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
1203 iln->n_passthroughcount); );
1205 /* set memory cursors */
1207 iln->inlined_iinstr_cursor = iln->inlined_iinstr;
1208 iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
1210 /* allocate temporary buffers */
1212 iln->javalocals = DMNEW(s4, iln->jd->maxlocals);
1214 /* loop over basic blocks */
1216 o_bptr = iln->jd->basicblocks;
1217 for (; o_bptr; o_bptr = o_bptr->next) {
1219 if (o_bptr->flags < BBREACHED) {
1221 /* ignore the dummy end block */
1223 if (o_bptr->icount == 0 && o_bptr->next == NULL) {
1224 /* enter the following block as translation, for exception handler ranges */
1225 inline_block_translation(iln, o_bptr, iln->inlined_basicblocks_cursor);
1230 printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
1232 o_bptr->nr, o_bptr->flags, o_bptr->type,
1234 method_println(iln->m);
1237 n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1239 /* enter it in the blockmap */
1241 inline_block_translation(iln, o_bptr, n_bptr);
1243 close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
1247 len = o_bptr->icount;
1248 o_iptr = o_bptr->iinstr;
1251 printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
1253 o_bptr->nr, o_bptr->flags, o_bptr->type,
1255 method_println(iln->m);
1256 show_basicblock(iln->jd, o_bptr, SHOW_STACK);
1259 if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
1260 /* create an inlined clone of this block */
1262 n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1265 /* enter it in the blockmap */
1267 inline_block_translation(iln, o_bptr, n_bptr);
1269 /* initialize the javalocals */
1271 MCOPY(iln->javalocals, n_bptr->javalocals, s4, iln->jd->maxlocals);
1276 /* continue caller block */
1278 n_bptr = iln->inlined_basicblocks_cursor - 1;
1279 icount = n_bptr->icount;
1281 /* translate the javalocals */
1283 jl = translate_javalocals(iln, o_bptr->javalocals);
1284 iln->inline_start_instruction->sx.s23.s3.inlineinfo->javalocals_start = jl;
1286 MCOPY(iln->javalocals, jl, s4, iln->jd->maxlocals);
1289 /* iterate over the ICMDs of this block */
1294 while (--len >= 0) {
1296 DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false, SHOW_STACK);
1299 /* handle calls that will be inlined */
1301 if (nextcall && o_iptr == nextcall->callerins) {
1303 /* write the inlining prolog */
1305 (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
1306 icount += nextcall->prolog_instructioncount;
1308 /* end current block, or glue blocks together */
1310 n_bptr->icount = icount;
1312 if (nextcall->blockbefore) {
1313 close_prolog_block(iln, n_bptr, nextcall);
1319 /* check if the result is a local variable */
1321 if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
1322 && o_iptr->dst.varindex < iln->jd->localcount)
1324 nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
1327 nextcall->n_resultlocal = -1;
1329 /* set memory pointers in the callee */
1331 nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
1332 nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
1336 DOLOG( printf("%sentering inline ", indent);
1337 show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1339 rewrite_method(nextcall);
1341 DOLOG( printf("%sleaving inline ", indent);
1342 show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1344 /* update memory cursors */
1346 assert(nextcall->inlined_iinstr_cursor
1347 <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
1348 assert(nextcall->inlined_basicblocks_cursor
1349 == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
1350 iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
1351 iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
1353 /* start new block, or glue blocks together */
1355 if (nextcall->blockafter) {
1356 n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
1360 n_bptr = iln->inlined_basicblocks_cursor - 1;
1361 icount = n_bptr->icount;
1365 /* emit inlining epilog */
1367 emit_inlining_epilog(iln, nextcall, o_iptr);
1368 icount++; /* XXX epilog instructions */
1370 /* proceed to next call */
1372 nextcall = nextcall->next;
1375 n_iptr = (iln->inlined_iinstr_cursor++);
1376 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1378 switch (o_iptr->opc) {
1380 if (iln->depth == 0)
1389 if (iln->depth == 0)
1392 retidx = iln->varmap[o_iptr->s1.varindex];
1393 if (iln->n_resultlocal != -1) {
1394 /* store result in a local variable */
1396 DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
1397 /* This relies on the same sequence of types for */
1398 /* ?STORE and ?RETURN opcodes. */
1399 n_iptr->opc = ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN);
1400 n_iptr->s1.varindex = retidx;
1401 n_iptr->dst.varindex = iln->n_resultlocal;
1402 n_iptr->sx.s23.s3.javaindex = UNUSED; /* XXX set real javaindex? */
1407 n_iptr = (iln->inlined_iinstr_cursor++);
1408 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1411 else if ((retidx < resultjd->localcount && iln->blockafter)
1412 || !iln->blockafter) /* XXX do we really always need the MOVE? */
1414 /* local must not become outvar, insert a MOVE */
1416 n_iptr->opc = ICMD_MOVE;
1417 n_iptr->s1.varindex = retidx;
1418 retidx = inline_new_temp_variable(resultjd,
1419 resultjd->var[retidx].type);
1420 n_iptr->dst.varindex = retidx;
1422 n_iptr = (iln->inlined_iinstr_cursor++);
1423 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1427 if (iln->blockafter) {
1428 n_iptr->opc = ICMD_GOTO;
1429 n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
1430 inline_add_block_reference(iln, &(n_iptr->dst.block));
1433 n_iptr->opc = ICMD_NOP;
1437 if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
1438 n_iptr->opc = ICMD_NOP;
1447 inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
1450 DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
1459 /* end of basic block */
1461 if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
1462 close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
1463 n_bptr->icount = icount;
1465 DOLOG( printf("closed body block:\n");
1466 show_basicblock(resultjd, n_bptr, SHOW_STACK); );
1469 n_bptr->icount = icount;
1470 assert(iln->parent);
1471 if (retidx != UNUSED)
1472 iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
1476 bm = iln->ctx->blockmap;
1477 for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
1478 assert(bm->iln && bm->o_block && bm->n_block);
1480 inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block);
1483 #if !defined(NDEBUG)
1485 inline_target_ref *ref;
1488 if (!iln->depth || *(ref->ref) != INLINE_RETURN_REFERENCE(iln)) {
1489 DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
1490 (void*)*(ref->ref)) );
1500 static exception_entry * inline_exception_tables(inline_node *iln,
1501 exception_entry *n_extable,
1502 exception_entry **prevextable)
1506 exception_entry *et;
1510 assert(prevextable);
1512 child = iln->children;
1515 n_extable = inline_exception_tables(child, n_extable, prevextable);
1516 child = child->next;
1517 } while (child != iln->children);
1520 et = iln->jd->exceptiontable;
1521 for (; et != NULL; et = et->down) {
1523 MZERO(n_extable, exception_entry, 1);
1524 n_extable->start = inline_map_block(iln, et->start , iln);
1525 n_extable->end = inline_map_block(iln, et->end , iln);
1526 n_extable->handler = inline_map_block(iln, et->handler, iln);
1527 n_extable->catchtype = et->catchtype;
1530 (*prevextable)->down = n_extable;
1532 *prevextable = n_extable;
1537 if (iln->handler_monitorexit) {
1538 exception_entry **activehandlers;
1540 MZERO(n_extable, exception_entry, 1);
1541 n_extable->start = iln->inlined_basicblocks;
1542 n_extable->end = iln->inlined_basicblocks_cursor;
1543 n_extable->handler = iln->handler_monitorexit;
1544 n_extable->catchtype.any = NULL; /* finally */
1547 (*prevextable)->down = n_extable;
1549 *prevextable = n_extable;
1553 /* We have to protect the created handler with the same handlers */
1554 /* that protect the method body itself. */
1556 for (scope = iln; scope->parent != NULL; scope = scope->parent) {
1558 activehandlers = scope->o_handlers;
1559 assert(activehandlers);
1561 while (*activehandlers) {
1563 assert(scope->parent);
1565 MZERO(n_extable, exception_entry, 1);
1566 n_extable->start = iln->handler_monitorexit;
1567 n_extable->end = iln->handler_monitorexit + 1; /* XXX ok in this case? */
1568 n_extable->handler = inline_map_block(scope->parent,
1569 (*activehandlers)->handler,
1571 n_extable->catchtype = (*activehandlers)->catchtype;
1574 (*prevextable)->down = n_extable;
1576 *prevextable = n_extable;
1588 static void inline_locals(inline_node *iln)
1594 iln->varmap = create_variable_map(iln);
1596 child = iln->children;
1599 inline_locals(child);
1600 child = child->next;
1601 } while (child != iln->children);
1604 if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
1605 iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
1606 if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
1607 iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
1608 if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
1609 iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
1613 static void inline_interface_variables(inline_node *iln)
1620 resultjd = iln->ctx->resultjd;
1622 resultjd->interface_map = DMNEW(interface_info, 5*iln->ctx->maxinoutdepth);
1623 for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
1624 resultjd->interface_map[i].flags = UNUSED;
1626 for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
1627 assert(bptr->indepth <= iln->ctx->maxinoutdepth);
1628 assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
1630 for (i=0; i<bptr->indepth; ++i) {
1631 v = &(resultjd->var[bptr->invars[i]]);
1633 v->flags &= ~PREALLOC;
1634 v->flags &= ~INMEMORY;
1635 assert(bptr->invars[i] >= resultjd->localcount);
1637 if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1638 resultjd->interface_map[5*i + v->type].flags = v->flags;
1641 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1645 for (i=0; i<bptr->outdepth; ++i) {
1646 v = &(resultjd->var[bptr->outvars[i]]);
1648 v->flags &= ~PREALLOC;
1649 v->flags &= ~INMEMORY;
1650 assert(bptr->outvars[i] >= resultjd->localcount);
1652 if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1653 resultjd->interface_map[5*i + v->type].flags = v->flags;
1656 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1663 static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
1668 builtintable_entry *bte;
1673 child = iln->children;
1676 inline_write_exception_handlers(master, child);
1677 child = child->next;
1678 } while (child != iln->children);
1681 if (iln->synchronize) {
1682 /* create the monitorexit handler */
1683 n_bptr = create_block(master, iln, iln, NULL, NULL,
1684 iln->n_passthroughcount + 1);
1685 n_bptr->type = BBTYPE_EXH;
1686 n_bptr->flags = BBFINISHED;
1688 exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1689 n_bptr->invars[iln->n_passthroughcount] = exvar;
1691 iln->handler_monitorexit = n_bptr;
1693 /* ACONST / ALOAD */
1695 n_ins = master->inlined_iinstr_cursor++;
1696 if (iln->m->flags & ACC_STATIC) {
1697 n_ins->opc = ICMD_ACONST;
1698 n_ins->sx.val.c.cls = iln->m->class;
1699 n_ins->flags.bits = INS_FLAG_CLASS;
1702 n_ins->opc = ICMD_ALOAD;
1703 n_ins->s1.varindex = iln->synclocal;
1704 assert(n_ins->s1.varindex != UNUSED);
1706 /* XXX could be PREALLOCed for builtin call */
1707 syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1708 n_ins->dst.varindex = syncvar;
1713 bte = builtintable_get_internal(LOCK_monitor_exit);
1715 n_ins = master->inlined_iinstr_cursor++;
1716 n_ins->opc = ICMD_BUILTIN;
1717 n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
1718 n_ins->sx.s23.s2.args = DMNEW(s4, n_ins->s1.argcount);
1719 n_ins->sx.s23.s2.args[0] = syncvar;
1720 for (i=0; i < iln->n_passthroughcount + 1; ++i) {
1721 n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
1723 n_ins->sx.s23.s3.bte = bte;
1728 n_ins = master->inlined_iinstr_cursor++;
1729 n_ins->opc = ICMD_ATHROW;
1730 n_ins->flags.bits = 0;
1731 n_ins->s1.varindex = exvar;
1734 /* close basic block */
1736 close_block(iln, iln, n_bptr, iln->n_passthroughcount);
1742 /* second pass driver *********************************************************/
1744 static bool test_inlining(inline_node *iln, jitdata *jd,
1750 exception_entry *n_ext;
1751 exception_entry *prevext;
1757 #if !defined(NDEBUG)
1758 static int debug_verify_inlined_code = 1; /* XXX */
1759 static int debug_compile_inlined_code_counter = 0;
1762 DOLOG( dump_inline_tree(iln, 0); );
1764 assert(iln && jd && resultjd);
1768 n_ins = DMNEW(instruction, iln->cumul_instructioncount);
1769 MZERO(n_ins, instruction, iln->cumul_instructioncount);
1770 iln->inlined_iinstr = n_ins;
1772 n_bb = DMNEW(basicblock, iln->cumul_basicblockcount);
1773 MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
1774 iln->inlined_basicblocks = n_bb;
1776 iln->ctx->blockmap = DMNEW(inline_block_map, iln->cumul_blockmapcount);
1778 n_jd = jit_jitdata_new(iln->m);
1779 n_jd->flags = jd->flags;
1780 iln->ctx->resultjd = n_jd;
1784 /* create the local_map */
1786 n_jd->local_map = DMNEW(s4, 5*iln->cumul_maxlocals);
1787 for (i=0; i<5*iln->cumul_maxlocals; ++i)
1788 n_jd->local_map[i] = UNUSED;
1790 /* create / coalesce local variables */
1798 n_jd->localcount = n_jd->vartop;
1800 /* extra variables for verification (DEBUG) */
1802 #if !defined(NDEBUG)
1803 if (debug_verify_inlined_code) {
1804 n_jd->vartop += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
1805 if (n_jd->vartop > n_jd->varcount) {
1807 n_jd->var = DMREALLOC(n_jd->var, varinfo, n_jd->varcount, n_jd->vartop);
1808 n_jd->varcount = n_jd->vartop;
1813 /* write inlined code */
1815 rewrite_method(iln);
1817 /* create exception handlers */
1819 inline_write_exception_handlers(iln, iln);
1821 /* write the dummy end block */
1823 n_bptr = create_block(iln, iln, iln, NULL, NULL, 0);
1824 n_bptr->flags = BBUNDEF;
1825 n_bptr->type = BBTYPE_STD;
1827 /* store created code in jitdata */
1829 n_jd->basicblocks = iln->inlined_basicblocks;
1830 n_jd->basicblockindex = NULL;
1831 n_jd->instructioncount = iln->cumul_instructioncount;
1832 n_jd->instructions = iln->inlined_iinstr;
1834 /* link the basic blocks (dummy end block is not counted) */
1836 n_jd->basicblockcount = (iln->inlined_basicblocks_cursor - iln->inlined_basicblocks) - 1;
1837 for (i=0; i<n_jd->basicblockcount + 1; ++i)
1838 n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
1840 n_jd->basicblocks[i-1].next = NULL;
1842 /* check basicblock numbers */
1844 #if !defined(NDEBUG)
1845 jit_check_basicblock_numbers(n_jd);
1848 /* create the exception table */
1850 if (iln->cumul_exceptiontablelength) {
1851 exception_entry *tableend;
1853 n_ext = DMNEW(exception_entry, iln->cumul_exceptiontablelength);
1855 tableend = inline_exception_tables(iln, n_ext, &prevext);
1856 assert(tableend == n_ext + iln->cumul_exceptiontablelength);
1858 prevext->down = NULL;
1860 n_jd->exceptiontablelength = iln->cumul_exceptiontablelength;
1861 n_jd->exceptiontable = n_ext;
1867 /*******************************************************************************/
1870 memcpy(n_cd, jd->cd, sizeof(codegendata));
1872 n_cd->method = NULL; /* XXX */
1873 n_jd->maxlocals = iln->cumul_maxlocals;
1874 n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
1876 inline_post_process(n_jd);
1878 inline_interface_variables(iln);
1880 #if defined(ENABLE_VERIFIER) && !defined(NDEBUG)
1881 if (debug_verify_inlined_code) {
1882 debug_verify_inlined_code = 0;
1883 DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
1884 if (!typecheck(n_jd)) {
1885 *exceptionptr = NULL;
1886 DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
1890 DOLOG( printf("VERIFICATION PASSED.\n") );
1892 debug_verify_inlined_code = 1;
1894 #endif /* defined(ENABLE_VERIFIER) */
1896 /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
1898 n_jd->rd->freemem = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
1899 #if defined(HAS_4BYTE_STACKSLOT)
1900 n_jd->rd->freemem_2 = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
1903 #if !defined(NDEBUG)
1904 if (n_jd->instructioncount >= inline_debug_min_size
1905 && n_jd->instructioncount <= inline_debug_max_size)
1907 if (debug_compile_inlined_code_counter >= inline_debug_start_counter
1908 && debug_compile_inlined_code_counter <= inline_debug_end_counter)
1913 #if !defined(NDEBUG)
1914 inline_count_methods++;
1916 /* inline_debug_log++; */
1918 printf("==== %d.INLINE ==================================================================\n", debug_compile_inlined_code_counter);
1919 printf("\ninline tree:\n");
1920 dump_inline_tree(iln, 0);
1921 n_jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE | JITDATA_FLAG_SHOWDISASSEMBLE;
1922 /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
1923 printf("-------- DONE -----------------------------------------------------------\n");
1926 /* inline_debug_log--; */
1930 #if !defined(NDEBUG)
1931 debug_compile_inlined_code_counter++;
1938 /* first pass: build inlining tree ********************************************/
1940 static bool inline_analyse_callee(inline_node *caller,
1942 basicblock *callerblock,
1943 instruction *calleriptr,
1945 exception_entry **handlers,
1948 inline_node *cn; /* the callee inline_node */
1954 /* create an inline tree node */
1956 cn = DNEW(inline_node);
1957 MZERO(cn, inline_node, 1);
1959 cn->ctx = caller->ctx;
1961 cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
1962 isstatic = (callee->flags & ACC_STATIC);
1964 /* get the intermediate representation of the callee */
1966 if (!inline_jit_compile(cn))
1969 /* info about the call site */
1971 cn->depth = caller->depth + 1;
1972 cn->callerblock = callerblock;
1973 cn->callerins = calleriptr;
1974 cn->callerpc = callerpc;
1975 cn->o_handlers = handlers;
1976 cn->n_handlercount = caller->n_handlercount + nhandlers;
1978 /* determine if we need basic block boundaries before/after */
1980 cn->blockbefore = false;
1981 cn->blockafter = false;
1983 if (cn->jd->branchtoentry)
1984 cn->blockbefore = true;
1986 if (cn->jd->branchtoend)
1987 cn->blockafter = true;
1989 if (cn->jd->returncount > 1)
1990 cn->blockafter = true;
1992 /* XXX make safer and reusable (maybe store last real block) */
1993 for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
1996 if (cn->jd->returnblock != bptr)
1997 cn->blockafter = true;
1999 /* info about the callee */
2001 cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
2002 cn->prolog_instructioncount = callee->parseddesc->paramcount + 1;
2003 cn->epilog_instructioncount = 1; /* INLINE_END */
2004 cn->extra_instructioncount = 0;
2006 /* we need a CHECKNULL for instance methods */
2009 cn->prolog_instructioncount += 1;
2011 /* deal with synchronized callees */
2013 if (cn->synchronize) {
2015 builtintable_entry *bte;
2017 /* we need basic block boundaries because of the handler */
2019 cn->blockbefore = true;
2020 cn->blockafter = true;
2022 /* for synchronized instance methods */
2023 /* we need an ASTORE in the prolog */
2026 cn->prolog_instructioncount += 1;
2027 cn->localsoffset += 1;
2030 /* and exception handler */
2031 /* ALOAD, builtin_monitorexit, ATHROW */
2033 cn->extra_instructioncount += 3;
2035 /* exception table entries */
2037 caller->cumul_exceptiontablelength += 1 + cn->n_handlercount;
2039 /* we must call the builtins */
2041 bte = builtintable_get_internal(LOCK_monitor_enter);
2043 if (md->memuse > cn->regdata->memuse)
2044 cn->regdata->memuse = md->memuse;
2045 if (md->argintreguse > cn->regdata->argintreguse)
2046 cn->regdata->argintreguse = md->argintreguse;
2048 bte = builtintable_get_internal(LOCK_monitor_exit);
2050 if (md->memuse > cn->regdata->memuse)
2051 cn->regdata->memuse = md->memuse;
2052 if (md->argintreguse > cn->regdata->argintreguse)
2053 cn->regdata->argintreguse = md->argintreguse;
2055 caller->ctx->calls_others = true;
2058 /* determine pass-through variables */
2060 i = calleriptr->s1.argcount - callee->parseddesc->paramcount; /* max # of pass-though vars */
2062 cn->n_passthroughvars = DMNEW(s4, i);
2064 for (argi = calleriptr->s1.argcount - 1; argi >= callee->parseddesc->paramcount; --argi) {
2065 s4 idx = calleriptr->sx.s23.s2.args[argi];
2066 if (idx >= caller->jd->localcount) {
2067 cn->n_passthroughvars[j] = idx;
2071 DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
2075 cn->n_selfpassthroughcount = j;
2076 cn->n_passthroughcount = caller->n_passthroughcount + cn->n_selfpassthroughcount;
2078 /* insert the node into the inline tree */
2080 insert_inline_node(caller, cn);
2082 /* analyse recursively */
2084 if (!inline_inline_intern(callee, cn))
2087 /* subtract one block if we continue the caller block */
2089 if (!cn->blockbefore)
2090 cn->cumul_basicblockcount -= 1;
2092 /* add exception handler block for synchronized callees */
2094 if (cn->synchronize) {
2095 caller->ctx->master->cumul_basicblockcount++;
2096 caller->ctx->master->cumul_blockmapcount++;
2099 /* cumulate counters */
2101 caller->cumul_instructioncount += cn->prolog_instructioncount;
2102 caller->cumul_instructioncount += cn->epilog_instructioncount;
2103 caller->cumul_instructioncount += cn->extra_instructioncount;
2104 caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
2106 caller->cumul_basicblockcount += cn->cumul_basicblockcount;
2107 caller->cumul_blockmapcount += cn->cumul_blockmapcount;
2108 caller->cumul_exceptiontablelength += cn->cumul_exceptiontablelength;
2109 if (cn->cumul_maxlocals > caller->cumul_maxlocals)
2110 caller->cumul_maxlocals = cn->cumul_maxlocals;
2112 if (caller->cumul_basicblockcount > 10*caller->ctx->master->jd->basicblockcount) {
2114 printf("STOPPING to avoid code explosion (%d blocks)\n",
2115 caller->cumul_basicblockcount);
2120 /* XXX extra block after inlined call */
2121 if (cn->blockafter) {
2122 caller->cumul_basicblockcount += 1;
2123 caller->cumul_blockmapcount += 1;
2130 static bool inline_inline_intern(methodinfo *m, inline_node *iln)
2135 int opcode; /* invocation opcode */
2137 inline_node *active;
2138 exception_entry **handlers;
2139 exception_entry *ex;
2148 /* initialize cumulative counters */
2150 iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
2151 iln->cumul_exceptiontablelength += mjd->exceptiontablelength;
2153 /* iterate over basic blocks */
2155 for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
2157 /* ignore dummy end blocks (but count them for the blockmap) */
2159 iln->cumul_blockmapcount++;
2160 if (bptr->icount > 0 || bptr->next != NULL)
2161 iln->cumul_basicblockcount++;
2163 /* skip dead code */
2165 if (bptr->flags < BBREACHED)
2168 /* allocate the buffer of active exception handlers */
2169 /* XXX this wastes some memory, but probably it does not matter */
2171 handlers = DMNEW(exception_entry*, mjd->exceptiontablelength + 1);
2173 /* determine the active exception handlers for this block */
2174 /* XXX maybe the handlers of a block should be part of our IR */
2175 /* XXX this should share code with the type checkers */
2177 for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
2178 if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
2179 handlers[nhandlers++] = ex;
2182 handlers[nhandlers] = NULL;
2185 iptr = bptr->iinstr;
2187 iln->instructioncount += len;
2188 iln->cumul_instructioncount += len;
2190 for (; --len >= 0; ++iptr) {
2195 /****************************************/
2198 case ICMD_INVOKEVIRTUAL:
2199 case ICMD_INVOKESPECIAL:
2200 case ICMD_INVOKESTATIC:
2201 case ICMD_INVOKEINTERFACE:
2203 if (!INSTRUCTION_IS_UNRESOLVED(iptr)) {
2204 callee = iptr->sx.s23.s3.fmiref->p.method;
2208 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Code_Table") == 0
2209 && (strcmp(callee->name->text, "of") == 0
2210 || strcmp(callee->name->text, "set") == 0))
2212 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Compressor") == 0
2213 && (strcmp(callee->name->text, "output") == 0))
2215 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Decompressor") == 0
2216 && (strcmp(callee->name->text, "getcode") == 0))
2218 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Output_Buffer") == 0
2219 && (strcmp(callee->name->text, "putbyte") == 0))
2221 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Input_Buffer") == 0
2222 && (strcmp(callee->name->text, "getbyte") == 0
2223 || strcmp(callee->name->text, "readbytes") == 0
2228 if (callee->jcodelength > 0)
2232 if (callee->flags & ACC_NATIVE)
2235 if (iln->depth >= 3)
2238 if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
2239 || opcode == ICMD_INVOKESPECIAL)) {
2240 speculative = false;
2244 if (callee->flags & ACC_METHOD_MONOMORPHIC) {
2247 && strncmp(callee->class->name->text, "java/", 5) != 0
2248 && strncmp(callee->class->name->text, "gnu/", 4) != 0
2251 DOLOG( printf("SPECULATIVE INLINE: "); method_println(callee); );
2257 /* polymorphic call site */
2261 for (active = iln; active; active = active->parent) {
2262 if (callee == active->m) {
2263 DOLOG( printf("RECURSIVE!\n") );
2270 if (!inline_analyse_callee(iln, callee,
2273 iln->instructioncount - len - 1 /* XXX ugly */,
2279 method_add_assumption_monomorphic(callee, iln->ctx->master->m);
2290 /* extra ICMD_MOVE may be necessary */
2291 iln->cumul_instructioncount++;
2296 /* end of basic block */
2303 /* post processing ************************************************************/
2305 #define POSTPROCESS_SRC(varindex) live[varindex]--
2306 #define POSTPROCESS_DST(varindex) live[varindex]++
2308 #define POSTPROCESS_SRCOP(s) POSTPROCESS_SRC(iptr->s.varindex)
2309 #define POSTPROCESS_DSTOP(d) POSTPROCESS_DST(iptr->d.varindex)
2311 #define MARKSAVED(varindex) jd->var[varindex].flags |= SAVEDVAR
2313 #define MARK_ALL_SAVED \
2315 for (i=0; i<jd->vartop; ++i) \
2320 static void inline_post_process(jitdata *jd)
2326 icmdtable_entry_t *icmdt;
2329 builtintable_entry *bte;
2331 /* reset the SAVEDVAR flag of all variables */
2333 for (i=0; i<jd->vartop; ++i)
2334 jd->var[i].flags &= ~SAVEDVAR;
2336 /* allocate the life counters */
2338 live = DMNEW(s4, jd->vartop);
2339 MZERO(live, s4, jd->vartop);
2341 /* iterate over all basic blocks */
2343 for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
2344 if (bptr->flags < BBREACHED)
2347 /* make invars live */
2349 for (i=0; i<bptr->indepth; ++i)
2350 POSTPROCESS_DST(bptr->invars[i]);
2352 iptr = bptr->iinstr;
2353 iend = iptr + bptr->icount;
2355 for (; iptr < iend; ++iptr) {
2357 icmdt = &(icmd_table[iptr->opc]);
2359 switch (icmdt->dataflow) {
2361 POSTPROCESS_SRCOP(sx.s23.s3);
2363 POSTPROCESS_SRCOP(sx.s23.s2);
2365 POSTPROCESS_SRCOP(s1);
2367 if (icmdt->flags & ICMDTABLE_CALLS) {
2368 jd->isleafmethod = false;
2374 POSTPROCESS_SRCOP(sx.s23.s2);
2377 POSTPROCESS_SRCOP(s1);
2379 if (icmdt->flags & ICMDTABLE_CALLS) {
2380 jd->isleafmethod = false;
2384 POSTPROCESS_DSTOP(dst);
2388 for (i=0; i<iptr->s1.argcount; ++i) {
2389 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
2391 if (icmdt->flags & ICMDTABLE_CALLS) {
2392 jd->isleafmethod = false;
2395 POSTPROCESS_DSTOP(dst);
2399 INSTRUCTION_GET_METHODDESC(iptr, md);
2401 jd->isleafmethod = false;
2402 for (i=0; i<md->paramcount; ++i) {
2403 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
2405 for (; i<iptr->s1.argcount; ++i) {
2406 MARKSAVED(iptr->sx.s23.s2.args[i]);
2408 if (md->returntype.type != TYPE_VOID)
2409 POSTPROCESS_DSTOP(dst);
2413 bte = iptr->sx.s23.s3.bte;
2415 goto post_process_call;
2421 } /* end instruction loop */
2423 /* consume outvars */
2425 for (i=0; i<bptr->outdepth; ++i)
2426 POSTPROCESS_SRC(bptr->outvars[i]);
2428 #if !defined(NDEBUG)
2429 for (i=jd->localcount; i < jd->vartop; ++i)
2430 assert(live[i] == 0);
2433 } /* end basic block loop */
2437 /* main driver function *******************************************************/
2439 bool inline_inline(jitdata *jd, jitdata **resultjd)
2448 DOLOG( printf("==== INLINE ==================================================================\n");
2449 show_method(jd, SHOW_STACK); );
2451 iln = DNEW(inline_node);
2452 MZERO(iln, inline_node, 1);
2454 iln->ctx = DNEW(inline_context);
2455 MZERO(iln->ctx, inline_context, 1);
2456 iln->ctx->master = iln;
2457 iln->ctx->calls_others = false;
2460 iln->regdata = jd->rd;
2461 iln->ctx->next_debugnr = 1; /* XXX debug */
2463 iln->blockbefore = true;
2464 iln->blockafter = true;
2466 /* we cannot use m->instructioncount because it may be greater than
2467 * the actual number of instructions in the basic blocks. */
2468 iln->instructioncount = 0;
2469 iln->cumul_instructioncount = 0;
2470 iln->cumul_basicblockcount = 1 /* dummy end block */;
2472 if (inline_inline_intern(m, iln)) {
2474 DOLOG( printf("==== TEST INLINE =============================================================\n"); );
2477 test_inlining(iln, jd, resultjd);
2480 DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
2487 * These are local overrides for various environment variables in Emacs.
2488 * Please do not remove this and leave it at the end of the file, where
2489 * Emacs will automagically detect them.
2490 * ---------------------------------------------------------------------
2493 * indent-tabs-mode: t
2497 * vim:noexpandtab:sw=4:ts=4: