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 5925 2006-11-05 23:11:27Z 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 #define INLINE_VERBOSE
72 bool inline_debug_log = 0;
73 bool inline_debug_log_names = 0;
74 int inline_debug_start_counter = 0;
75 int inline_debug_max_size = INT_MAX;
76 int inline_debug_min_size = 0;
77 int inline_debug_end_counter = INT_MAX;
78 int inline_count_methods = 0;
79 #define DOLOG(code) do{ if (inline_debug_log) { code; } }while(0)
85 /* types **********************************************************************/
87 typedef struct inline_node inline_node;
88 typedef struct inline_target_ref inline_target_ref;
89 typedef struct inline_context inline_context;
90 typedef struct inline_block_map inline_block_map;
97 inline_node *children;
98 inline_node *next; /* next node at this depth */
99 inline_node *prev; /* prev node at this depth */
100 int depth; /* inlining depth, 0 for root */
102 /* info about the call site (if depth > 0)*/
103 inline_node *parent; /* node of the caller (NULL for root) */
104 basicblock *callerblock; /* original block containing the INVOKE* */
105 instruction *callerins; /* the original INVOKE* instruction */
107 s4 *n_passthroughvars;
108 int n_passthroughcount;
109 int n_selfpassthroughcount; /* # of pass-through vars of the call itself */
110 exception_entry **o_handlers;
111 int n_handlercount; /* # of handlers protecting this call */
113 int synclocal; /* variable used for synchr., or UNUSED */
115 bool blockbefore; /* block boundary before inlined body? */
116 bool blockafter; /* block boundary after inlined body? */
118 /* info about the callee */
120 int prolog_instructioncount; /* # of ICMDs in the inlining prolog */
121 int epilog_instructioncount; /* # of ICMDs in the inlining epilog */
122 int extra_instructioncount;
123 int instructioncount;
124 bool synchronize; /* do we have to synchronize enter/exit? */
125 basicblock *handler_monitorexit; /* handler for synchronized inlinees */
128 /* cumulative values */
129 int cumul_instructioncount; /* ICMDs in this node and its children */
130 int cumul_basicblockcount; /* BBs started by this node and its children */
131 int cumul_blockmapcount;
133 int cumul_exceptiontablelength;
136 instruction *inlined_iinstr;
137 instruction *inlined_iinstr_cursor;
138 basicblock *inlined_basicblocks;
139 basicblock *inlined_basicblocks_cursor;
142 registerdata *regdata;
145 inline_target_ref *refs;
146 instruction *inline_start_instruction;
153 struct inline_target_ref {
154 inline_target_ref *next;
159 struct inline_block_map {
165 struct inline_context {
170 int next_block_number;
171 inline_block_map *blockmap;
178 int next_debugnr; /* XXX debug */
182 /* prototypes *****************************************************************/
184 static bool inline_inline_intern(methodinfo *m, inline_node *iln);
185 static void inline_post_process(jitdata *jd);
188 /* debug helpers **************************************************************/
191 #include "inline_debug.inc"
193 void inline_print_stats()
195 printf("inlined callers: %d\n", inline_count_methods);
200 /* compilation of callees *****************************************************/
202 static bool inline_jit_compile_intern(jitdata *jd)
206 /* XXX should share code with jit.c */
210 /* XXX initialize the static function's class */
214 /* call the compiler passes ***********************************************/
216 /* call parse pass */
218 DOLOG( log_message_class("Parsing ", m->class) );
223 /* call stack analysis pass */
225 if (!stack_analyse(jd)) {
233 static bool inline_jit_compile(inline_node *iln)
239 /* XXX should share code with jit.c */
245 #if defined(ENABLE_THREADS)
246 /* enter a monitor on the method */
247 lock_monitor_enter((java_objectheader *) m);
250 /* allocate jitdata structure and fill it */
252 jd = jit_jitdata_new(m);
255 jd->flags = 0; /* XXX */
257 /* initialize the register allocator */
261 /* setup the codegendata memory */
263 /* XXX do a pseudo setup */
264 jd->cd = DNEW(codegendata);
265 MZERO(jd->cd, codegendata, 1);
266 jd->cd->maxstack = m->maxstack;
268 /* XXX uses too much dump memory codegen_setup(jd); */
270 /* now call internal compile function */
272 r = inline_jit_compile_intern(jd);
275 iln->regdata = jd->rd;
278 /* free some memory */
281 #if defined(ENABLE_JIT)
282 # if defined(ENABLE_INTRP)
290 #if defined(ENABLE_THREADS)
291 /* leave the monitor */
292 lock_monitor_exit((java_objectheader *) m );
299 /* inlining tree handling *****************************************************/
301 static void insert_inline_node(inline_node *parent, inline_node *child)
306 assert(parent && child);
308 child->parent = parent;
310 child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
312 first = parent->children;
314 /* insert as only node */
315 parent->children = child;
321 /* {there is at least one child already there} */
323 /* XXX is this search necessary, or could we always add at the end? */
326 while (succ->callerpc < child->callerpc) {
329 /* insert as last node */
330 child->prev = first->prev;
332 child->prev->next = child;
333 child->next->prev = child;
338 assert(succ->callerpc > child->callerpc);
340 /* insert before succ */
342 child->prev = succ->prev;
344 child->prev->next = child;
345 child->next->prev = child;
349 /* variable handling **********************************************************/
351 static s4 inline_new_variable(jitdata *jd, s4 type, s4 flags)
356 index = jd->vartop++;
357 if (index >= jd->varcount) {
358 newcount = jd->vartop * 2; /* XXX */
359 jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, newcount);
360 MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
361 jd->varcount = newcount;
364 jd->var[index].type = type;
365 jd->var[index].flags = flags;
371 static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
376 v = &(origjd->var[origidx]);
378 newidx = inline_new_variable(jd, v->type, v->flags);
380 jd->var[newidx].vv = v->vv;
386 static s4 inline_new_temp_variable(jitdata *jd, s4 type)
388 return inline_new_variable(jd, type, 0);
392 static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
399 idx = inline_new_variable_clone(jd, origjd, index);
407 static s4 *create_variable_map(inline_node *callee)
417 /* create the variable mapping */
419 varmap = DMNEW(s4, callee->jd->varcount);
420 for (i=0; i<callee->jd->varcount; ++i)
423 /* translate local variables */
425 for (i=0; i<callee->m->maxlocals; ++i) {
426 for (t=0; t<5; ++t) {
427 idx = callee->jd->local_map[5*i + t];
431 v = &(callee->jd->var[idx]);
432 assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
433 v->type = t; /* XXX restore if it is TYPE_VOID */
435 avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
437 if (avail == UNUSED) {
438 avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, idx);
439 callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
446 /* for synchronized instance methods we need an extra local */
448 if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
449 n_idx = callee->localsoffset - 1;
451 assert(callee->parent);
452 assert(n_idx == callee->parent->localsoffset + callee->parent->m->maxlocals);
454 avail = callee->ctx->resultjd->local_map[5*n_idx + TYPE_ADR];
456 if (avail == UNUSED) {
457 avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
458 callee->ctx->resultjd->local_map[5*n_idx + TYPE_ADR] = avail;
461 callee->synclocal = avail;
464 callee->synclocal = UNUSED;
471 /* basic block translation ****************************************************/
473 #define INLINE_RETURN_REFERENCE(callee) \
474 ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
477 static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
479 inline_target_ref *ref;
481 ref = DNEW(inline_target_ref);
483 ref->next = iln->refs;
488 static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
493 assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
495 ctx->blockmap[ctx->blockmap_index].iln = iln;
496 ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
497 ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
499 ctx->blockmap_index++;
503 static basicblock * inline_map_block(inline_node *iln,
505 inline_node *targetiln)
507 inline_block_map *bm;
508 inline_block_map *bmend;
516 bm = iln->ctx->blockmap;
517 bmend = bm + iln->ctx->blockmap_index;
520 assert(bm->iln && bm->o_block && bm->n_block);
521 if (bm->o_block == o_block && bm->iln == targetiln)
527 return NULL; /* not reached */
531 static void inline_resolve_block_refs(inline_target_ref **refs,
535 inline_target_ref *ref;
536 inline_target_ref *prev;
541 if (*(ref->ref) == o_bptr) {
543 #if defined(INLINE_VERBOSE)
544 if (inline_debug_log) {
545 if ((ptrint) o_bptr < (0x333+100)) { /* XXX */
546 printf("resolving RETURN block reference %p -> new L%03d (%p)\n",
547 (void*)o_bptr, n_bptr->nr, (void*)n_bptr);
550 printf("resolving block reference old L%03d (%p) -> new L%03d (%p)\n",
551 o_bptr->nr, (void*)o_bptr, n_bptr->nr, (void*)n_bptr);
556 *(ref->ref) = n_bptr;
558 prev->next = ref->next;
572 /* basic block creation *******************************************************/
574 static basicblock * create_block(inline_node *container,
578 inline_target_ref **refs,
591 assert(indepth >= 0);
593 n_bptr = container->inlined_basicblocks_cursor++;
595 assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
597 BASICBLOCK_INIT(n_bptr, iln->m);
599 n_bptr->iinstr = container->inlined_iinstr_cursor;
600 n_bptr->next = n_bptr + 1;
601 n_bptr->nr = container->ctx->next_block_number++;
602 n_bptr->indepth = indepth;
603 n_bptr->flags = BBFINISHED; /* XXX */
605 if (indepth > container->ctx->maxinoutdepth)
606 container->ctx->maxinoutdepth = indepth;
609 n_bptr->invars = DMNEW(s4, indepth);
612 for (i=0; i<indepth; ++i)
613 n_bptr->invars[i] = -1; /* XXX debug */
615 /* pass-through variables enter the block */
617 outer = inner->parent;
618 while (outer != NULL) {
619 depth = outer->n_passthroughcount;
621 assert(depth + inner->n_selfpassthroughcount <= indepth);
623 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
624 varidx = inner->n_passthroughvars[i];
626 inline_new_variable_clone(container->ctx->resultjd,
629 n_bptr->invars[depth + i] = newvaridx;
630 outer->varmap[varidx] = newvaridx;
633 outer = outer->parent;
637 n_bptr->invars = NULL;
640 /* XXX move this to callers with o_bptr != NULL? */
643 inline_resolve_block_refs(refs, o_bptr, n_bptr);
649 /* XXX for the verifier. should not be here */
651 dv = DMNEW(varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
652 MZERO(dv, varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
653 n_bptr->inlocals = dv;
660 static basicblock * create_body_block(inline_node *iln,
661 basicblock *o_bptr, s4 *varmap)
666 n_bptr = create_block(iln, iln, iln, o_bptr, &(iln->refs),
667 o_bptr->indepth + iln->n_passthroughcount);
669 n_bptr->type = o_bptr->type;
670 n_bptr->flags = o_bptr->flags;
672 /* translate the invars of the original block */
674 for (i=0; i<o_bptr->indepth; ++i) {
675 n_bptr->invars[iln->n_passthroughcount + i] =
676 inline_translate_variable(iln->ctx->resultjd, iln->jd,
685 static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
692 /* number of return variables */
694 retcount = (callee->n_resultlocal == -1
695 && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
697 /* start the epilog block */
699 n_bptr = create_block(caller, caller, callee, INLINE_RETURN_REFERENCE(callee),
700 &(callee->refs), callee->n_passthroughcount + retcount);
702 /* return variable */
705 idx = inline_new_variable(caller->ctx->resultjd,
706 callee->m->parseddesc->returntype.type, 0 /* XXX */);
707 n_bptr->invars[callee->n_passthroughcount] = idx;
708 varmap[callee->callerins->dst.varindex] = idx;
711 n_bptr->flags = /* XXX original block flags */ BBFINISHED;
712 n_bptr->type = BBTYPE_STD;
718 static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
725 n_bptr->outdepth = outdepth;
726 n_bptr->outvars = DMNEW(s4, outdepth);
728 for (i=0; i<outdepth; ++i)
729 n_bptr->outvars[i] = 0; /* XXX debug */
731 if (outdepth > iln->ctx->maxinoutdepth)
732 iln->ctx->maxinoutdepth = outdepth;
734 /* pass-through variables leave the block */
736 outer = inner->parent;
737 while (outer != NULL) {
738 depth = outer->n_passthroughcount;
740 assert(depth + inner->n_selfpassthroughcount <= outdepth);
742 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
743 varidx = inner->n_passthroughvars[i];
744 n_bptr->outvars[depth + i] =
745 inline_translate_variable(iln->ctx->resultjd,
751 outer = outer->parent;
756 static void close_prolog_block(inline_node *iln,
758 inline_node *nextcall)
760 /* XXX add original outvars! */
761 close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
763 /* pass-through variables */
765 DOLOG( printf("closed prolog block:\n");
766 show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
770 static void close_body_block(inline_node *iln,
779 close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
781 /* translate the outvars of the original block */
784 for (i=0; i<o_bptr->outdepth; ++i) {
785 n_bptr->outvars[iln->n_passthroughcount + i] =
786 inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
790 /* set the return variable, if any */
794 n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
799 /* inlined code generation ****************************************************/
801 static s4 emit_inlining_prolog(inline_node *iln,
813 insinfo_inline *insinfo;
816 assert(iln && callee && o_iptr);
819 md = calleem->parseddesc;
820 isstatic = (calleem->flags & ACC_STATIC);
822 localindex = callee->localsoffset + md->paramslots;
824 for (i=md->paramcount-1; i>=0; --i) {
827 n_ins = (iln->inlined_iinstr_cursor++);
828 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
830 type = md->paramtypes[i].type;
832 localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
833 assert(callee->regdata);
835 /* translate the argument variable */
837 argvar = varmap[o_iptr->sx.s23.s2.args[i]];
838 assert(argvar != UNUSED);
840 /* remove preallocation from the argument variable */
842 iln->ctx->resultjd->var[argvar].flags &= ~(PREALLOC | INMEMORY);
844 /* check the instance slot against NULL */
846 if (!isstatic && i == 0) {
847 assert(type == TYPE_ADR);
848 n_ins->opc = ICMD_CHECKNULL;
849 n_ins->s1.varindex = argvar;
850 n_ins->dst.varindex = n_ins->s1.varindex;
851 n_ins->line = o_iptr->line;
853 n_ins = (iln->inlined_iinstr_cursor++);
854 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
857 /* store argument into local variable of inlined callee */
859 if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != UNUSED)
861 /* this value is used in the callee */
863 if (i == 0 && callee->synclocal != UNUSED) {
864 /* we also need it for synchronization, so copy it */
865 assert(type == TYPE_ADR);
866 n_ins->opc = ICMD_COPY;
869 n_ins->opc = ICMD_ISTORE + type;
871 n_ins->s1.varindex = argvar;
872 n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
873 assert(n_ins->dst.varindex != UNUSED);
875 else if (i == 0 && callee->synclocal != UNUSED) {
876 /* the value is not used inside the callee, but we need it for */
877 /* synchronization */
878 /* XXX In this case it actually makes no sense to create a */
879 /* separate synchronization variable. */
881 n_ins->opc = ICMD_NOP;
884 /* this value is not used, pop it */
886 n_ins->opc = ICMD_POP;
887 n_ins->s1.varindex = argvar;
889 n_ins->line = o_iptr->line;
891 DOLOG( printf("%sprolog: ", iln->indent);
892 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
895 /* ASTORE for synchronized instance methods */
897 if (callee->synclocal != UNUSED) {
898 n_ins = (iln->inlined_iinstr_cursor++);
899 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
901 n_ins->opc = ICMD_ASTORE;
902 n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
903 n_ins->dst.varindex = callee->synclocal;
904 n_ins->line = o_iptr->line;
906 assert(n_ins->s1.varindex != UNUSED);
909 /* INLINE_START instruction */
911 n_ins = (iln->inlined_iinstr_cursor++);
912 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
914 insinfo = DNEW(insinfo_inline);
915 insinfo->method = callee->m;
916 insinfo->outer = iln->m;
917 insinfo->synclocal = callee->synclocal;
918 insinfo->synchronize = callee->synchronize;
920 n_ins->opc = ICMD_INLINE_START;
921 n_ins->sx.s23.s3.inlineinfo = insinfo;
922 n_ins->line = o_iptr->line;
923 iln->inline_start_instruction = n_ins;
925 DOLOG( printf("%sprolog: ", iln->indent);
926 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
932 static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
936 assert(iln && callee && o_iptr);
937 assert(iln->inline_start_instruction);
939 /* INLINE_END instruction */
941 n_ins = (iln->inlined_iinstr_cursor++);
942 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
944 n_ins->opc = ICMD_INLINE_END;
945 n_ins->sx.s23.s3.inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
946 n_ins->line = o_iptr->line;
948 DOLOG( printf("%sepilog: ", iln->indent);
949 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
953 #define TRANSLATE_VAROP(vo) \
954 n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
957 static void inline_clone_instruction(inline_node *iln,
964 icmdtable_entry_t *icmdt;
965 builtintable_entry *bte;
968 branch_target_t *table;
969 lookup_target_t *lookup;
974 icmdt = &(icmd_table[o_iptr->opc]);
976 switch (icmdt->dataflow) {
981 TRANSLATE_VAROP(sx.s23.s3);
983 TRANSLATE_VAROP(sx.s23.s2);
989 TRANSLATE_VAROP(sx.s23.s2);
995 TRANSLATE_VAROP(dst);
999 n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1000 for (i=0; i<n_iptr->s1.argcount; ++i) {
1001 n_iptr->sx.s23.s2.args[i] =
1002 inline_translate_variable(jd, origjd, varmap,
1003 o_iptr->sx.s23.s2.args[i]);
1005 TRANSLATE_VAROP(dst);
1009 INSTRUCTION_GET_METHODDESC(n_iptr, md);
1011 n_iptr->s1.argcount += iln->n_passthroughcount;
1012 n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1013 for (i=0; i<o_iptr->s1.argcount; ++i) {
1014 n_iptr->sx.s23.s2.args[i] =
1015 inline_translate_variable(jd, origjd, varmap,
1016 o_iptr->sx.s23.s2.args[i]);
1018 for (scope = iln; scope != NULL; scope = scope->parent) {
1019 for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
1020 n_iptr->sx.s23.s2.args[i++] =
1021 scope->parent->varmap[scope->n_passthroughvars[j]];
1024 if (md->returntype.type != TYPE_VOID)
1025 TRANSLATE_VAROP(dst);
1029 bte = n_iptr->sx.s23.s3.bte;
1037 switch (icmdt->controlflow) {
1039 TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
1043 inline_add_block_reference(iln, &(n_iptr->dst.block));
1047 inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
1051 i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
1053 table = DMNEW(branch_target_t, i);
1054 MCOPY(table, o_iptr->dst.table, branch_target_t, i);
1055 n_iptr->dst.table = table;
1058 inline_add_block_reference(iln, &(table->block));
1064 inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
1066 i = n_iptr->sx.s23.s2.lookupcount;
1067 lookup = DMNEW(lookup_target_t, i);
1068 MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
1069 n_iptr->dst.lookup = lookup;
1072 inline_add_block_reference(iln, &(lookup->target.block));
1080 static void rewrite_method(inline_node *iln)
1084 instruction *o_iptr;
1085 instruction *n_iptr;
1086 inline_node *nextcall;
1088 inline_block_map *bm;
1093 char indent[100]; /* XXX debug */
1099 resultjd = iln->ctx->resultjd;
1103 nextcall = iln->children;
1106 for (i=0; i<iln->depth; ++i)
1109 iln->indent = indent;
1111 DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
1112 printf("%s(passthrough: %d+%d)\n",
1113 indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
1114 iln->n_passthroughcount); );
1116 /* set memory cursors */
1118 iln->inlined_iinstr_cursor = iln->inlined_iinstr;
1119 iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
1121 /* loop over basic blocks */
1123 o_bptr = iln->jd->basicblocks;
1124 for (; o_bptr; o_bptr = o_bptr->next) {
1126 if (o_bptr->flags < BBREACHED) {
1128 /* ignore the dummy end block */
1130 if (o_bptr->icount == 0 && o_bptr->next == NULL) {
1131 /* enter the following block as translation, for exception handler ranges */
1132 inline_block_translation(iln, o_bptr, iln->inlined_basicblocks_cursor);
1137 printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
1139 o_bptr->nr, o_bptr->flags, o_bptr->type,
1141 method_println(iln->m);
1144 n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1146 /* enter it in the blockmap */
1148 inline_block_translation(iln, o_bptr, n_bptr);
1150 close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
1154 len = o_bptr->icount;
1155 o_iptr = o_bptr->iinstr;
1158 printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
1160 o_bptr->nr, o_bptr->flags, o_bptr->type,
1162 method_println(iln->m);
1163 show_basicblock(iln->jd, o_bptr, SHOW_STACK);
1166 if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
1167 /* create an inlined clone of this block */
1169 n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1172 /* enter it in the blockmap */
1174 inline_block_translation(iln, o_bptr, n_bptr);
1177 /* continue caller block */
1179 n_bptr = iln->inlined_basicblocks_cursor - 1;
1180 icount = n_bptr->icount;
1186 while (--len >= 0) {
1188 DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false, SHOW_STACK);
1191 /* handle calls that will be inlined */
1193 if (nextcall && o_iptr == nextcall->callerins) {
1195 /* write the inlining prolog */
1197 (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
1198 icount += nextcall->prolog_instructioncount;
1200 /* end current block, or glue blocks together */
1202 n_bptr->icount = icount;
1204 if (nextcall->blockbefore) {
1205 close_prolog_block(iln, n_bptr, nextcall);
1211 /* check if the result is a local variable */
1213 if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
1214 && o_iptr->dst.varindex < iln->jd->localcount)
1216 nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
1219 nextcall->n_resultlocal = -1;
1221 /* set memory pointers in the callee */
1223 nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
1224 nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
1228 DOLOG( printf("%sentering inline ", indent);
1229 show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1231 rewrite_method(nextcall);
1233 DOLOG( printf("%sleaving inline ", indent);
1234 show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1236 /* update memory cursors */
1238 assert(nextcall->inlined_iinstr_cursor
1239 <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
1240 assert(nextcall->inlined_basicblocks_cursor
1241 == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
1242 iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
1243 iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
1245 /* start new block, or glue blocks together */
1247 if (nextcall->blockafter) {
1248 n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
1252 n_bptr = iln->inlined_basicblocks_cursor - 1;
1253 icount = n_bptr->icount;
1257 /* emit inlining epilog */
1259 emit_inlining_epilog(iln, nextcall, o_iptr);
1260 icount++; /* XXX epilog instructions */
1262 /* proceed to next call */
1264 nextcall = nextcall->next;
1267 n_iptr = (iln->inlined_iinstr_cursor++);
1268 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1270 switch (o_iptr->opc) {
1272 if (iln->depth == 0)
1281 if (iln->depth == 0)
1284 retidx = iln->varmap[o_iptr->s1.varindex];
1285 if (iln->n_resultlocal != -1) {
1286 /* store result in a local variable */
1288 DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
1289 /* This relies on the same sequence of types for */
1290 /* ?STORE and ?RETURN opcodes. */
1291 n_iptr->opc = ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN);
1292 n_iptr->s1.varindex = retidx;
1293 n_iptr->dst.varindex = iln->n_resultlocal;
1298 n_iptr = (iln->inlined_iinstr_cursor++);
1299 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1302 else if ((retidx < resultjd->localcount && iln->blockafter)
1303 || !iln->blockafter) /* XXX do we really always need the MOVE? */
1305 /* local must not become outvar, insert a MOVE */
1307 n_iptr->opc = ICMD_MOVE;
1308 n_iptr->s1.varindex = retidx;
1309 retidx = inline_new_temp_variable(resultjd,
1310 resultjd->var[retidx].type);
1311 n_iptr->dst.varindex = retidx;
1313 n_iptr = (iln->inlined_iinstr_cursor++);
1314 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1318 if (iln->blockafter) {
1319 n_iptr->opc = ICMD_GOTO;
1320 n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
1321 inline_add_block_reference(iln, &(n_iptr->dst.block));
1324 n_iptr->opc = ICMD_NOP;
1328 if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
1329 n_iptr->opc = ICMD_NOP;
1338 inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
1341 DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
1350 /* end of basic block */
1352 if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
1353 close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
1354 n_bptr->icount = icount;
1356 DOLOG( printf("closed body block:\n");
1357 show_basicblock(resultjd, n_bptr, SHOW_STACK); );
1360 n_bptr->icount = icount;
1361 assert(iln->parent);
1362 if (retidx != UNUSED)
1363 iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
1367 bm = iln->ctx->blockmap;
1368 for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
1369 assert(bm->iln && bm->o_block && bm->n_block);
1371 inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block);
1374 #if !defined(NDEBUG)
1376 inline_target_ref *ref;
1379 if (!iln->depth || *(ref->ref) != INLINE_RETURN_REFERENCE(iln)) {
1380 DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
1381 (void*)*(ref->ref)) );
1391 static exception_entry * inline_exception_tables(inline_node *iln,
1392 exception_entry *n_extable,
1393 exception_entry **prevextable)
1397 exception_entry *et;
1401 assert(prevextable);
1403 child = iln->children;
1406 n_extable = inline_exception_tables(child, n_extable, prevextable);
1407 child = child->next;
1408 } while (child != iln->children);
1411 et = iln->jd->exceptiontable;
1412 for (; et != NULL; et = et->down) {
1414 MZERO(n_extable, exception_entry, 1);
1415 n_extable->start = inline_map_block(iln, et->start , iln);
1416 n_extable->end = inline_map_block(iln, et->end , iln);
1417 n_extable->handler = inline_map_block(iln, et->handler, iln);
1418 n_extable->catchtype = et->catchtype;
1421 (*prevextable)->down = n_extable;
1423 *prevextable = n_extable;
1428 if (iln->handler_monitorexit) {
1429 exception_entry **activehandlers;
1431 MZERO(n_extable, exception_entry, 1);
1432 n_extable->start = iln->inlined_basicblocks;
1433 n_extable->end = iln->inlined_basicblocks_cursor;
1434 n_extable->handler = iln->handler_monitorexit;
1435 n_extable->catchtype.any = NULL; /* finally */
1438 (*prevextable)->down = n_extable;
1440 *prevextable = n_extable;
1444 /* We have to protect the created handler with the same handlers */
1445 /* that protect the method body itself. */
1447 for (scope = iln; scope->parent != NULL; scope = scope->parent) {
1449 activehandlers = scope->o_handlers;
1450 assert(activehandlers);
1452 while (*activehandlers) {
1454 assert(scope->parent);
1456 MZERO(n_extable, exception_entry, 1);
1457 n_extable->start = iln->handler_monitorexit;
1458 n_extable->end = iln->handler_monitorexit + 1; /* XXX ok in this case? */
1459 n_extable->handler = inline_map_block(scope->parent,
1460 (*activehandlers)->handler,
1462 n_extable->catchtype = (*activehandlers)->catchtype;
1465 (*prevextable)->down = n_extable;
1467 *prevextable = n_extable;
1479 static void inline_locals(inline_node *iln)
1485 iln->varmap = create_variable_map(iln);
1487 child = iln->children;
1490 inline_locals(child);
1491 child = child->next;
1492 } while (child != iln->children);
1495 if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
1496 iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
1497 if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
1498 iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
1499 if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
1500 iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
1504 static void inline_interface_variables(inline_node *iln)
1511 resultjd = iln->ctx->resultjd;
1513 resultjd->interface_map = DMNEW(interface_info, 5*iln->ctx->maxinoutdepth);
1514 for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
1515 resultjd->interface_map[i].flags = UNUSED;
1517 for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
1518 assert(bptr->indepth <= iln->ctx->maxinoutdepth);
1519 assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
1521 for (i=0; i<bptr->indepth; ++i) {
1522 v = &(resultjd->var[bptr->invars[i]]);
1524 v->flags &= ~PREALLOC;
1525 v->flags &= ~INMEMORY;
1526 assert(bptr->invars[i] >= resultjd->localcount);
1528 if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1529 resultjd->interface_map[5*i + v->type].flags = v->flags;
1532 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1536 for (i=0; i<bptr->outdepth; ++i) {
1537 v = &(resultjd->var[bptr->outvars[i]]);
1539 v->flags &= ~PREALLOC;
1540 v->flags &= ~INMEMORY;
1541 assert(bptr->outvars[i] >= resultjd->localcount);
1543 if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1544 resultjd->interface_map[5*i + v->type].flags = v->flags;
1547 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1554 static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
1559 builtintable_entry *bte;
1565 child = iln->children;
1568 inline_write_exception_handlers(master, child);
1569 child = child->next;
1570 } while (child != iln->children);
1573 if (iln->synchronize) {
1574 /* create the monitorexit handler */
1575 n_bptr = create_block(master, iln, iln, NULL, NULL,
1576 iln->n_passthroughcount + 1);
1577 n_bptr->type = BBTYPE_EXH;
1578 n_bptr->flags = BBFINISHED;
1580 exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1581 n_bptr->invars[iln->n_passthroughcount] = exvar;
1583 iln->handler_monitorexit = n_bptr;
1585 /* ACONST / ALOAD */
1587 n_ins = master->inlined_iinstr_cursor++;
1588 if (iln->m->flags & ACC_STATIC) {
1589 n_ins->opc = ICMD_ACONST;
1590 n_ins->sx.val.c.cls = iln->m->class;
1591 n_ins->flags.bits = INS_FLAG_CLASS;
1594 n_ins->opc = ICMD_ALOAD;
1595 n_ins->s1.varindex = iln->synclocal;
1596 assert(n_ins->s1.varindex != UNUSED);
1598 /* XXX could be PREALLOCed for builtin call */
1599 syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1600 n_ins->dst.varindex = syncvar;
1605 bte = builtintable_get_internal(LOCK_monitor_exit);
1607 n_ins = master->inlined_iinstr_cursor++;
1608 n_ins->opc = ICMD_BUILTIN;
1609 n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
1610 n_ins->sx.s23.s2.args = DMNEW(s4, n_ins->s1.argcount);
1611 n_ins->sx.s23.s2.args[0] = syncvar;
1612 for (i=0; i < iln->n_passthroughcount + 1; ++i) {
1613 n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
1615 n_ins->sx.s23.s3.bte = bte;
1620 n_ins = master->inlined_iinstr_cursor++;
1621 n_ins->opc = ICMD_ATHROW;
1622 n_ins->flags.bits = 0;
1623 n_ins->s1.varindex = exvar;
1626 /* close basic block */
1628 close_block(iln, iln, n_bptr, iln->n_passthroughcount);
1634 /* second pass driver *********************************************************/
1636 static bool test_inlining(inline_node *iln, jitdata *jd,
1642 exception_entry *n_ext;
1643 exception_entry *prevext;
1649 static int debug_verify_inlined_code = 1; /* XXX */
1650 #if !defined(NDEBUG)
1651 static int debug_compile_inlined_code_counter = 0;
1654 DOLOG( dump_inline_tree(iln, 0); );
1656 assert(iln && jd && resultjd);
1660 n_ins = DMNEW(instruction, iln->cumul_instructioncount);
1661 iln->inlined_iinstr = n_ins;
1663 n_bb = DMNEW(basicblock, iln->cumul_basicblockcount);
1664 MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
1665 iln->inlined_basicblocks = n_bb;
1667 iln->ctx->blockmap = DMNEW(inline_block_map, iln->cumul_blockmapcount);
1669 n_jd = jit_jitdata_new(iln->m);
1670 n_jd->flags = jd->flags;
1671 iln->ctx->resultjd = n_jd;
1675 /* create the local_map */
1677 n_jd->local_map = DMNEW(s4, 5*iln->cumul_maxlocals);
1678 for (i=0; i<5*iln->cumul_maxlocals; ++i)
1679 n_jd->local_map[i] = UNUSED;
1681 /* create / coalesce local variables */
1689 n_jd->localcount = n_jd->vartop;
1691 /* extra variables for verification (DEBUG) */
1693 if (debug_verify_inlined_code) {
1694 n_jd->vartop += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
1695 if (n_jd->vartop > n_jd->varcount) {
1697 n_jd->var = DMREALLOC(n_jd->var, varinfo, n_jd->varcount, n_jd->vartop);
1698 n_jd->varcount = n_jd->vartop;
1702 /* write inlined code */
1704 rewrite_method(iln);
1706 /* create exception handlers */
1708 inline_write_exception_handlers(iln, iln);
1710 /* write the dummy end block */
1712 n_bptr = create_block(iln, iln, iln, NULL, NULL, 0);
1713 n_bptr->flags = BBUNDEF;
1714 n_bptr->type = BBTYPE_STD;
1716 /* store created code in jitdata */
1718 n_jd->basicblocks = iln->inlined_basicblocks;
1719 n_jd->basicblockindex = NULL;
1720 n_jd->instructioncount = iln->cumul_instructioncount;
1721 n_jd->instructions = iln->inlined_iinstr;
1723 /* link the basic blocks (dummy end block is not counted) */
1725 n_jd->basicblockcount = (iln->inlined_basicblocks_cursor - iln->inlined_basicblocks) - 1;
1726 for (i=0; i<n_jd->basicblockcount + 1; ++i)
1727 n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
1729 n_jd->basicblocks[i-1].next = NULL;
1731 /* check basicblock numbers */
1733 #if !defined(NDEBUG)
1734 jit_check_basicblock_numbers(n_jd);
1737 /* create the exception table */
1739 if (iln->cumul_exceptiontablelength) {
1740 exception_entry *tableend;
1742 n_ext = DMNEW(exception_entry, iln->cumul_exceptiontablelength);
1744 tableend = inline_exception_tables(iln, n_ext, &prevext);
1745 assert(tableend == n_ext + iln->cumul_exceptiontablelength);
1747 prevext->down = NULL;
1749 n_jd->exceptiontablelength = iln->cumul_exceptiontablelength;
1750 n_jd->exceptiontable = n_ext;
1756 /*******************************************************************************/
1759 memcpy(n_cd, jd->cd, sizeof(codegendata));
1761 n_cd->method = NULL; /* XXX */
1762 n_jd->maxlocals = iln->cumul_maxlocals;
1763 n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
1765 inline_post_process(n_jd);
1767 inline_interface_variables(iln);
1769 #if defined(ENABLE_VERIFIER)
1770 if (debug_verify_inlined_code) {
1771 debug_verify_inlined_code = 0;
1772 DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
1773 if (!typecheck(n_jd)) {
1774 *exceptionptr = NULL;
1775 DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
1779 DOLOG( printf("VERIFICATION PASSED.\n") );
1781 debug_verify_inlined_code = 1;
1783 #endif /* defined(ENABLE_VERIFIER) */
1785 /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
1787 n_jd->rd->freemem = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
1788 #if defined(HAS_4BYTE_STACKSLOT)
1789 n_jd->rd->freemem_2 = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
1792 #if !defined(NDEBUG)
1793 if (n_jd->instructioncount >= inline_debug_min_size
1794 && n_jd->instructioncount <= inline_debug_max_size)
1796 if (debug_compile_inlined_code_counter >= inline_debug_start_counter
1797 && debug_compile_inlined_code_counter <= inline_debug_end_counter)
1802 #if !defined(NDEBUG)
1803 inline_count_methods++;
1805 /* inline_debug_log++; */
1807 printf("==== %d.INLINE ==================================================================\n", debug_compile_inlined_code_counter);
1808 printf("\ninline tree:\n");
1809 dump_inline_tree(iln, 0);
1810 n_jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE | JITDATA_FLAG_SHOWDISASSEMBLE;
1811 /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
1812 printf("-------- DONE -----------------------------------------------------------\n");
1815 /* inline_debug_log--; */
1819 #if !defined(NDEBUG)
1820 debug_compile_inlined_code_counter++;
1827 /* first pass: build inlining tree ********************************************/
1829 static bool inline_analyse_callee(inline_node *caller,
1831 basicblock *callerblock,
1832 instruction *calleriptr,
1834 exception_entry **handlers,
1837 inline_node *cn; /* the callee inline_node */
1844 /* create an inline tree node */
1846 cn = DNEW(inline_node);
1847 MZERO(cn, inline_node, 1);
1849 cn->ctx = caller->ctx;
1851 cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
1852 isstatic = (callee->flags & ACC_STATIC);
1854 /* get the intermediate representation of the callee */
1856 if (!inline_jit_compile(cn))
1859 /* info about the call site */
1861 cn->depth = caller->depth + 1;
1862 cn->callerblock = callerblock;
1863 cn->callerins = calleriptr;
1864 cn->callerpc = callerpc;
1865 cn->o_handlers = handlers;
1866 cn->n_handlercount = caller->n_handlercount + nhandlers;
1868 /* determine if we need basic block boundaries before/after */
1870 cn->blockbefore = false;
1871 cn->blockafter = false;
1873 if (cn->jd->branchtoentry)
1874 cn->blockbefore = true;
1876 if (cn->jd->branchtoend)
1877 cn->blockafter = true;
1879 if (cn->jd->returncount > 1)
1880 cn->blockafter = true;
1882 /* XXX make safer and reusable (maybe store last real block) */
1883 for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
1886 if (cn->jd->returnblock != bptr)
1887 cn->blockafter = true;
1889 /* info about the callee */
1891 cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
1892 cn->prolog_instructioncount = callee->parseddesc->paramcount + 1;
1893 cn->epilog_instructioncount = 1; /* INLINE_END */
1894 cn->extra_instructioncount = 0;
1896 /* we need a CHECKNULL for instance methods */
1899 cn->prolog_instructioncount += 1;
1901 /* deal with synchronized callees */
1903 if (cn->synchronize) {
1905 builtintable_entry *bte;
1907 /* we need basic block boundaries because of the handler */
1909 cn->blockbefore = true;
1910 cn->blockafter = true;
1912 /* for synchronized instance methods */
1913 /* we need an ASTORE in the prolog */
1916 cn->prolog_instructioncount += 1;
1917 cn->localsoffset += 1;
1920 /* and exception handler */
1921 /* ALOAD, builtin_monitorexit, ATHROW */
1923 cn->extra_instructioncount += 3;
1925 /* exception table entries */
1927 caller->cumul_exceptiontablelength += 1 + cn->n_handlercount;
1929 /* we must call the builtins */
1931 bte = builtintable_get_internal(LOCK_monitor_enter);
1933 if (md->memuse > cn->regdata->memuse)
1934 cn->regdata->memuse = md->memuse;
1935 if (md->argintreguse > cn->regdata->argintreguse)
1936 cn->regdata->argintreguse = md->argintreguse;
1938 bte = builtintable_get_internal(LOCK_monitor_exit);
1940 if (md->memuse > cn->regdata->memuse)
1941 cn->regdata->memuse = md->memuse;
1942 if (md->argintreguse > cn->regdata->argintreguse)
1943 cn->regdata->argintreguse = md->argintreguse;
1945 caller->ctx->calls_others = true;
1948 /* determine pass-through variables */
1950 i = calleriptr->s1.argcount - callee->parseddesc->paramcount; /* max # of pass-though vars */
1952 cn->n_passthroughvars = DMNEW(s4, i);
1954 for (argi = calleriptr->s1.argcount - 1; argi >= callee->parseddesc->paramcount; --argi) {
1955 s4 idx = calleriptr->sx.s23.s2.args[argi];
1956 if (idx >= caller->jd->localcount) {
1957 cn->n_passthroughvars[j] = idx;
1961 DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
1965 cn->n_selfpassthroughcount = j;
1966 cn->n_passthroughcount = caller->n_passthroughcount + cn->n_selfpassthroughcount;
1968 /* insert the node into the inline tree */
1970 insert_inline_node(caller, cn);
1972 /* analyse recursively */
1974 if (!inline_inline_intern(callee, cn))
1977 /* subtract one block if we continue the caller block */
1979 if (!cn->blockbefore)
1980 cn->cumul_basicblockcount -= 1;
1982 /* add exception handler block for synchronized callees */
1984 if (cn->synchronize) {
1985 caller->ctx->master->cumul_basicblockcount++;
1986 caller->ctx->master->cumul_blockmapcount++;
1989 /* cumulate counters */
1991 caller->cumul_instructioncount += cn->prolog_instructioncount;
1992 caller->cumul_instructioncount += cn->epilog_instructioncount;
1993 caller->cumul_instructioncount += cn->extra_instructioncount;
1994 caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
1996 caller->cumul_basicblockcount += cn->cumul_basicblockcount;
1997 caller->cumul_blockmapcount += cn->cumul_blockmapcount;
1998 caller->cumul_exceptiontablelength += cn->cumul_exceptiontablelength;
1999 if (cn->cumul_maxlocals > caller->cumul_maxlocals)
2000 caller->cumul_maxlocals = cn->cumul_maxlocals;
2002 if (caller->cumul_basicblockcount > 10*caller->ctx->master->jd->basicblockcount) {
2004 printf("STOPPING to avoid code explosion (%d blocks)\n",
2005 caller->cumul_basicblockcount);
2010 /* XXX extra block after inlined call */
2011 if (cn->blockafter) {
2012 caller->cumul_basicblockcount += 1;
2013 caller->cumul_blockmapcount += 1;
2020 static bool inline_inline_intern(methodinfo *m, inline_node *iln)
2025 int opcode; /* invocation opcode */
2027 inline_node *active;
2028 exception_entry **handlers;
2029 exception_entry *ex;
2038 /* initialize cumulative counters */
2040 iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
2041 iln->cumul_exceptiontablelength += mjd->exceptiontablelength;
2043 /* iterate over basic blocks */
2045 for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
2047 /* ignore dummy end blocks (but count them for the blockmap) */
2049 iln->cumul_blockmapcount++;
2050 if (bptr->icount > 0 || bptr->next != NULL)
2051 iln->cumul_basicblockcount++;
2053 /* skip dead code */
2055 if (bptr->flags < BBREACHED)
2058 /* allocate the buffer of active exception handlers */
2059 /* XXX this wastes some memory, but probably it does not matter */
2061 handlers = DMNEW(exception_entry*, mjd->exceptiontablelength + 1);
2063 /* determine the active exception handlers for this block */
2064 /* XXX maybe the handlers of a block should be part of our IR */
2065 /* XXX this should share code with the type checkers */
2067 for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
2068 if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
2069 handlers[nhandlers++] = ex;
2072 handlers[nhandlers] = NULL;
2075 iptr = bptr->iinstr;
2077 iln->instructioncount += len;
2078 iln->cumul_instructioncount += len;
2080 for (; --len >= 0; ++iptr) {
2085 /****************************************/
2088 case ICMD_INVOKEVIRTUAL:
2089 case ICMD_INVOKESPECIAL:
2090 case ICMD_INVOKESTATIC:
2091 case ICMD_INVOKEINTERFACE:
2093 if (!INSTRUCTION_IS_UNRESOLVED(iptr)) {
2094 callee = iptr->sx.s23.s3.fmiref->p.method;
2098 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Code_Table") == 0
2099 && (strcmp(callee->name->text, "of") == 0
2100 || strcmp(callee->name->text, "set") == 0))
2102 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Compressor") == 0
2103 && (strcmp(callee->name->text, "output") == 0))
2105 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Decompressor") == 0
2106 && (strcmp(callee->name->text, "getcode") == 0))
2108 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Output_Buffer") == 0
2109 && (strcmp(callee->name->text, "putbyte") == 0))
2111 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Input_Buffer") == 0
2112 && (strcmp(callee->name->text, "getbyte") == 0
2113 || strcmp(callee->name->text, "readbytes") == 0
2118 if (callee->jcodelength > 0)
2122 if (callee->flags & ACC_NATIVE)
2125 if (iln->depth >= 3)
2128 if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
2129 || opcode == ICMD_INVOKESPECIAL)) {
2130 speculative = false;
2134 if (callee->flags & ACC_METHOD_MONOMORPHIC) {
2137 && strncmp(callee->class->name->text, "java/", 5) != 0
2138 && strncmp(callee->class->name->text, "gnu/", 4) != 0
2141 printf("SPECULATIVE INLINE: "); method_println(callee);
2147 /* polymorphic call site */
2151 for (active = iln; active; active = active->parent) {
2152 if (callee == active->m) {
2153 DOLOG( printf("RECURSIVE!\n") );
2159 if (!inline_analyse_callee(iln, callee,
2162 iln->instructioncount - len - 1 /* XXX ugly */,
2168 method_add_assumption_monomorphic(callee, iln->ctx->master->m);
2179 /* extra ICMD_MOVE may be necessary */
2180 iln->cumul_instructioncount++;
2185 /* end of basic block */
2192 /* post processing ************************************************************/
2194 #define POSTPROCESS_SRC(varindex) live[varindex]--
2195 #define POSTPROCESS_DST(varindex) live[varindex]++
2197 #define POSTPROCESS_SRCOP(s) POSTPROCESS_SRC(iptr->s.varindex)
2198 #define POSTPROCESS_DSTOP(d) POSTPROCESS_DST(iptr->d.varindex)
2200 #define MARKSAVED(varindex) jd->var[varindex].flags |= SAVEDVAR
2202 #define MARK_ALL_SAVED \
2204 for (i=0; i<jd->vartop; ++i) \
2209 static void inline_post_process(jitdata *jd)
2215 icmdtable_entry_t *icmdt;
2218 builtintable_entry *bte;
2220 /* reset the SAVEDVAR flag of all variables */
2222 for (i=0; i<jd->vartop; ++i)
2223 jd->var[i].flags &= ~SAVEDVAR;
2225 /* allocate the life counters */
2227 live = DMNEW(s4, jd->vartop);
2228 MZERO(live, s4, jd->vartop);
2230 /* iterate over all basic blocks */
2232 for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
2233 if (bptr->flags < BBREACHED)
2236 /* make invars live */
2238 for (i=0; i<bptr->indepth; ++i)
2239 POSTPROCESS_DST(bptr->invars[i]);
2241 iptr = bptr->iinstr;
2242 iend = iptr + bptr->icount;
2244 for (; iptr < iend; ++iptr) {
2246 icmdt = &(icmd_table[iptr->opc]);
2248 switch (icmdt->dataflow) {
2250 POSTPROCESS_SRCOP(sx.s23.s3);
2252 POSTPROCESS_SRCOP(sx.s23.s2);
2254 POSTPROCESS_SRCOP(s1);
2256 if (icmdt->flags & ICMDTABLE_CALLS) {
2257 jd->isleafmethod = false;
2263 POSTPROCESS_SRCOP(sx.s23.s2);
2266 POSTPROCESS_SRCOP(s1);
2268 if (icmdt->flags & ICMDTABLE_CALLS) {
2269 jd->isleafmethod = false;
2273 POSTPROCESS_DSTOP(dst);
2277 for (i=0; i<iptr->s1.argcount; ++i) {
2278 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
2280 if (icmdt->flags & ICMDTABLE_CALLS) {
2281 jd->isleafmethod = false;
2284 POSTPROCESS_DSTOP(dst);
2288 INSTRUCTION_GET_METHODDESC(iptr, md);
2290 jd->isleafmethod = false;
2291 for (i=0; i<md->paramcount; ++i) {
2292 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
2294 for (; i<iptr->s1.argcount; ++i) {
2295 MARKSAVED(iptr->sx.s23.s2.args[i]);
2297 if (md->returntype.type != TYPE_VOID)
2298 POSTPROCESS_DSTOP(dst);
2302 bte = iptr->sx.s23.s3.bte;
2304 goto post_process_call;
2310 } /* end instruction loop */
2312 /* consume outvars */
2314 for (i=0; i<bptr->outdepth; ++i)
2315 POSTPROCESS_SRC(bptr->outvars[i]);
2317 #if !defined(NDEBUG)
2318 for (i=jd->localcount; i < jd->vartop; ++i)
2319 assert(live[i] == 0);
2322 } /* end basic block loop */
2326 /* main driver function *******************************************************/
2328 bool inline_inline(jitdata *jd, jitdata **resultjd)
2337 DOLOG( printf("==== INLINE ==================================================================\n");
2338 show_method(jd, SHOW_STACK); );
2340 iln = DNEW(inline_node);
2341 MZERO(iln, inline_node, 1);
2343 iln->ctx = DNEW(inline_context);
2344 MZERO(iln->ctx, inline_context, 1);
2345 iln->ctx->master = iln;
2346 iln->ctx->calls_others = false;
2349 iln->regdata = jd->rd;
2350 iln->ctx->next_debugnr = 1; /* XXX debug */
2352 iln->blockbefore = true;
2353 iln->blockafter = true;
2355 /* we cannot use m->instructioncount because it may be greater than
2356 * the actual number of instructions in the basic blocks. */
2357 iln->instructioncount = 0;
2358 iln->cumul_instructioncount = 0;
2359 iln->cumul_basicblockcount = 1 /* dummy end block */;
2361 if (inline_inline_intern(m, iln)) {
2363 DOLOG( printf("==== TEST INLINE =============================================================\n"); );
2366 test_inlining(iln, jd, resultjd);
2369 DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
2376 * These are local overrides for various environment variables in Emacs.
2377 * Please do not remove this and leave it at the end of the file, where
2378 * Emacs will automagically detect them.
2379 * ---------------------------------------------------------------------
2382 * indent-tabs-mode: t
2386 * vim:noexpandtab:sw=4:ts=4: