1 /* src/vm/jit/inline/inline.c - method inlining
3 Copyright (C) 1996-2005, 2006, 2007 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 $Id: inline.c 7813 2007-04-25 19:20:13Z twisti $
39 #include "mm/memory.h"
41 #include "threads/lock-common.h"
42 #include "threads/threads-common.h"
44 #include "toolbox/logging.h"
46 #include "vm/builtin.h"
47 #include "vm/global.h"
48 #include "vm/initialize.h"
50 #include "vm/jit/jit.h"
51 #include "vm/jit/parse.h"
52 #include "vm/jit/reg.h"
53 #include "vm/jit/show.h"
54 #include "vm/jit/stack.h"
56 #include "vm/jit/inline/inline.h"
57 #include "vm/jit/loop/loop.h"
59 #include "vm/jit/verify/typecheck.h"
61 #include "vmcore/class.h"
62 #include "vmcore/method.h"
63 #include "vmcore/options.h"
64 #include "vmcore/statistics.h"
67 /* algorithm tuning constants *************************************************/
69 /* Algorithm Selection */
70 /* Define exactly one of the following three to select the inlining */
73 /*#define INLINE_DEPTH_FIRST*/
74 /*#define INLINE_BREADTH_FIRST*/
75 #define INLINE_KNAPSACK
77 /* Parameters for knapsack heuristics: */
79 #if defined(INLINE_KNAPSACK)
81 #define INLINE_COUNTDOWN_INIT 1000
82 #define INLINE_COST_OFFSET -16
83 #define INLINE_COST_BUDGET 100
84 /*#define INLINE_WEIGHT_BUDGET 5.0*/
85 /*#define INLINE_ADD_NEGATIVE_TO_BUDGET*/
86 /*#define INLINE_MAX_DEPTH 3*/
87 /*#define INLINE_DIVIDE_COST_BY_FREQ */
91 /* Parameters for depth-first heuristics: */
93 #if defined(INLINE_DEPTH_FIRST)
95 #define INLINE_MAX_DEPTH 3
96 #define INLINE_MAX_BLOCK_EXPANSION 10
97 /*#define INLINE_MAX_ICMD_EXPANSION 10*/
98 /*#define INLINE_CANCEL_ON_THRESHOLD*/
102 /* Parameters for breadth-first heuristics: */
104 #if defined(INLINE_BREADTH_FIRST)
106 /*#define INLINE_MAX_BLOCK_EXPANSION 10*/
107 #define INLINE_MAX_ICMD_EXPANSION 5
112 /* debugging ******************************************************************/
115 #define INLINE_VERBOSE
116 #define DOLOG(code) do{ if (opt_inline_debug_log) { code; } }while(0)
121 #if defined(ENABLE_VERIFIER) && !defined(NDEBUG)
122 /* Define this to verify the resulting code after inlining. */
123 /* Note: This is only useful for development and may require patches to the */
125 /* #define INLINE_VERIFY_RESULT */
129 /* types **********************************************************************/
131 typedef struct inline_node inline_node;
132 typedef struct inline_target_ref inline_target_ref;
133 typedef struct inline_context inline_context;
134 typedef struct inline_block_map inline_block_map;
135 typedef struct inline_site inline_site;
136 typedef struct inline_candidate inline_candidate;
143 inline_node *children;
144 inline_node *next; /* next node at this depth */
145 inline_node *prev; /* prev node at this depth */
146 int depth; /* inlining depth, 0 for root */
148 /* info about the call site (if depth > 0)*/
149 inline_node *parent; /* node of the caller (NULL for root) */
150 basicblock *callerblock; /* original block containing the INVOKE* */
151 instruction *callerins; /* the original INVOKE* instruction */
153 s4 *n_passthroughvars;
154 int n_passthroughcount;
155 int n_selfpassthroughcount; /* # of pass-through vars of the call itself */
156 exception_entry **o_handlers;
157 int n_handlercount; /* # of handlers protecting this call */
159 int synclocal; /* variable used for synchr., or UNUSED */
160 bool isstatic; /* this is a static call */
162 bool blockbefore; /* block boundary before inlined body? */
163 bool blockafter; /* block boundary after inlined body? */
165 /* info about the callee */
167 int prolog_instructioncount; /* # of ICMDs in the inlining prolog */
168 int epilog_instructioncount; /* # of ICMDs in the inlining epilog */
169 int extra_instructioncount;
170 int extra_exceptiontablelength; /* # of extra handlers to put in caller */
171 bool synchronize; /* do we have to synchronize enter/exit? */
172 basicblock *handler_monitorexit; /* handler for synchronized inlinees */
175 /* cumulative values */
176 int cumul_instructioncount; /* ICMDs in this node and its children */
177 int cumul_basicblockcount; /* BBs started by this node and its children */
178 int cumul_basicblockcount_root; /* BBs that have to be added to the root */
179 /* node if this node is inlined */
180 int cumul_blockmapcount;
182 int cumul_exceptiontablelength;
185 instruction *inlined_iinstr;
186 instruction *inlined_iinstr_cursor;
187 basicblock *inlined_basicblocks;
188 basicblock *inlined_basicblocks_cursor;
191 registerdata *regdata;
194 inline_target_ref *refs;
195 instruction *inline_start_instruction;
203 struct inline_target_ref {
204 inline_target_ref *next;
213 struct inline_block_map {
219 struct inline_context {
224 inline_candidate *candidates;
226 int next_block_number;
227 inline_block_map *blockmap;
234 int next_debugnr; /* XXX debug */
238 bool speculative; /* true, if inlining would be speculative */
239 bool inlined; /* true, if this site has been inlined */
241 basicblock *bptr; /* basic block containing the call site */
242 instruction *iptr; /* the invocation instruction */
243 exception_entry **handlers; /* active handlers at the call site */
244 s4 nhandlers; /* number of active handlers */
245 s4 pc; /* PC of the invocation instruction */
248 struct inline_candidate {
249 inline_candidate *next;
259 /* prototypes *****************************************************************/
261 static bool inline_analyse_code(inline_node *iln);
262 static void inline_post_process(jitdata *jd);
265 /* debug helpers **************************************************************/
268 #include "inline_debug.inc"
272 /* statistics *****************************************************************/
274 /*#define INLINE_STATISTICS*/
277 #define INLINE_STATISTICS
280 #if defined(INLINE_STATISTICS)
281 int inline_stat_roots = 0;
282 int inline_stat_roots_transformed = 0;
283 int inline_stat_inlined_nodes = 0;
284 int inline_stat_max_depth = 0;
286 void inline_print_stats()
288 printf("inlining statistics:\n");
289 printf(" roots analysed : %d\n", inline_stat_roots);
290 printf(" roots transformed: %d\n", inline_stat_roots_transformed);
291 printf(" inlined nodes : %d\n", inline_stat_inlined_nodes);
292 printf(" max depth : %d\n", inline_stat_max_depth);
297 /* compilation of callees *****************************************************/
299 static bool inline_jit_compile_intern(jitdata *jd)
303 /* XXX should share code with jit.c */
307 /* XXX initialize the static function's class */
311 /* call the compiler passes ***********************************************/
313 /* call parse pass */
315 DOLOG( log_message_class("Parsing ", m->class) );
320 /* call stack analysis pass */
322 if (!stack_analyse(jd)) {
330 static bool inline_jit_compile(inline_node *iln)
336 /* XXX should share code with jit.c */
342 /* enter a monitor on the method */
344 LOCK_MONITOR_ENTER(m);
346 /* allocate jitdata structure and fill it */
348 jd = jit_jitdata_new(m);
351 jd->flags = 0; /* XXX */
353 /* initialize the register allocator */
357 /* setup the codegendata memory */
359 /* XXX do a pseudo setup */
360 jd->cd = DNEW(codegendata);
361 MZERO(jd->cd, codegendata, 1);
363 /* XXX uses too much dump memory codegen_setup(jd); */
365 /* now call internal compile function */
367 r = inline_jit_compile_intern(jd);
370 iln->regdata = jd->rd;
373 /* free some memory */
376 #if defined(ENABLE_JIT)
377 # if defined(ENABLE_INTRP)
385 /* leave the monitor */
387 LOCK_MONITOR_EXIT(m);
393 /* inlining tree handling *****************************************************/
395 static void inline_insert_inline_node(inline_node *parent, inline_node *child)
400 assert(parent && child);
402 child->parent = parent;
404 child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
406 first = parent->children;
408 /* insert as only node */
409 parent->children = child;
415 /* {there is at least one child already there} */
417 /* XXX is this search necessary, or could we always add at the end? */
420 while (succ->callerpc < child->callerpc) {
423 /* insert as last node */
424 child->prev = first->prev;
426 child->prev->next = child;
427 child->next->prev = child;
432 assert(succ->callerpc > child->callerpc);
434 /* insert before succ */
436 child->prev = succ->prev;
438 child->prev->next = child;
439 child->next->prev = child;
441 if (parent->children == succ)
442 parent->children = child;
446 static void inline_remove_inline_node(inline_node *parent, inline_node *child)
450 assert(child->parent == parent);
452 if (child->prev == child) {
453 /* remove the only child node */
454 parent->children = NULL;
457 child->prev->next = child->next;
458 child->next->prev = child->prev;
460 if (parent->children == child)
461 parent->children = child->next;
466 /* inlining candidate handling ************************************************/
468 #if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
469 static void inline_add_candidate(inline_context *ctx,
474 inline_candidate **link;
475 inline_candidate *cand;
477 cand = DNEW(inline_candidate);
478 #if defined(INLINE_DIVIDE_COST_BY_FREQ)
479 cand->freq = INLINE_COUNTDOWN_INIT - callee->hitcountdown;
483 #if defined(INLINE_KNAPSACK)
484 cand->cost = callee->jcodelength + INLINE_COST_OFFSET;
486 #if defined(INLINE_BREADTH_FIRST)
487 cand->cost = caller->depth;
489 cand->caller = caller;
490 cand->callee = callee;
493 cand->weight = (double)cand->cost / cand->freq;
495 for (link = &(ctx->candidates); ; link = &((*link)->next)) {
496 if (!*link || (*link)->weight > cand->weight) {
503 #endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
505 #if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
506 static inline_candidate * inline_pick_best_candidate(inline_context *ctx)
508 inline_candidate *cand;
510 cand = ctx->candidates;
513 ctx->candidates = cand->next;
517 #endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
519 #if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
520 static void inline_candidate_println(inline_candidate *cand)
522 printf("%10g (%5d / %5d) depth %2d ",
523 cand->weight, cand->cost, cand->freq, cand->caller->depth + 1);
524 method_println(cand->callee);
526 #endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
529 #if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
530 static void inline_candidates_println(inline_context *ctx)
532 inline_candidate *cand;
534 for (cand = ctx->candidates; cand != NULL; cand = cand->next) {
536 inline_candidate_println(cand);
539 #endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
542 /* variable handling **********************************************************/
544 static s4 inline_new_variable(jitdata *jd, s4 type, s4 flags)
549 index = jd->vartop++;
550 if (index >= jd->varcount) {
551 newcount = jd->vartop * 2; /* XXX */
552 jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, newcount);
553 MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
554 jd->varcount = newcount;
557 jd->var[index].type = type;
558 jd->var[index].flags = flags;
564 static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
569 v = &(origjd->var[origidx]);
571 newidx = inline_new_variable(jd, v->type, v->flags);
573 jd->var[newidx].vv = v->vv;
579 static s4 inline_new_temp_variable(jitdata *jd, s4 type)
581 return inline_new_variable(jd, type, 0);
585 static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
592 idx = inline_new_variable_clone(jd, origjd, index);
600 static s4 *create_variable_map(inline_node *callee)
609 /* create the variable mapping */
611 varmap = DMNEW(s4, callee->jd->varcount);
612 for (i=0; i<callee->jd->varcount; ++i)
615 /* translate local variables */
617 for (i=0; i<callee->m->maxlocals; ++i) {
618 for (t=0; t<5; ++t) {
619 varindex = callee->jd->local_map[5*i + t];
620 if (varindex == UNUSED)
623 v = &(callee->jd->var[varindex]);
624 assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
625 v->type = t; /* XXX restore if it is TYPE_VOID */
627 avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
629 if (avail == UNUSED) {
630 avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, varindex);
631 callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
634 varmap[varindex] = avail;
638 /* for synchronized instance methods we need an extra local */
640 if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
641 n_javaindex = callee->localsoffset - 1;
642 assert(n_javaindex >= 0);
643 assert(callee->parent);
644 assert(n_javaindex == callee->parent->localsoffset + callee->parent->m->maxlocals);
646 avail = callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR];
648 if (avail == UNUSED) {
649 avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
650 callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR] = avail;
653 callee->synclocal = avail;
656 callee->synclocal = UNUSED;
663 /* basic block translation ****************************************************/
665 #define INLINE_RETURN_REFERENCE(callee) \
666 ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
669 static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
671 inline_target_ref *ref;
673 ref = DNEW(inline_target_ref);
674 ref->ref.block = blockp;
675 ref->isnumber = false;
676 ref->next = iln->refs;
681 static void inline_add_blocknr_reference(inline_node *iln, s4 *nrp)
683 inline_target_ref *ref;
685 ref = DNEW(inline_target_ref);
687 ref->isnumber = true;
688 ref->next = iln->refs;
693 static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
698 assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
700 ctx->blockmap[ctx->blockmap_index].iln = iln;
701 ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
702 ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
704 ctx->blockmap_index++;
708 static basicblock * inline_map_block(inline_node *iln,
710 inline_node *targetiln)
712 inline_block_map *bm;
713 inline_block_map *bmend;
721 bm = iln->ctx->blockmap;
722 bmend = bm + iln->ctx->blockmap_index;
725 assert(bm->iln && bm->o_block && bm->n_block);
726 if (bm->o_block == o_block && bm->iln == targetiln)
732 return NULL; /* not reached */
736 static void inline_resolve_block_refs(inline_target_ref **refs,
741 inline_target_ref *ref;
742 inline_target_ref *prev;
745 for (ref = *refs; ref != NULL; ref = ref->next) {
746 if (ref->isnumber && !returnref) {
747 if (*(ref->ref.nr) == JAVALOCAL_FROM_RETADDR(o_bptr->nr)) {
748 *(ref->ref.nr) = JAVALOCAL_FROM_RETADDR(n_bptr->nr);
753 if (*(ref->ref.block) == o_bptr) {
754 *(ref->ref.block) = n_bptr;
765 /* remove this ref */
768 prev->next = ref->next;
777 /* basic block creation *******************************************************/
779 static basicblock * create_block(inline_node *container,
794 assert(indepth >= 0);
796 n_bptr = container->inlined_basicblocks_cursor++;
798 assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
800 BASICBLOCK_INIT(n_bptr, iln->m);
802 n_bptr->iinstr = container->inlined_iinstr_cursor;
803 n_bptr->next = n_bptr + 1;
804 n_bptr->nr = container->ctx->next_block_number++;
805 n_bptr->indepth = indepth;
806 n_bptr->flags = BBFINISHED; /* XXX */
808 /* set the inlineinfo of the new block */
810 if (iln->inline_start_instruction)
811 n_bptr->inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
813 if (indepth > container->ctx->maxinoutdepth)
814 container->ctx->maxinoutdepth = indepth;
817 n_bptr->invars = DMNEW(s4, indepth);
820 for (i=0; i<indepth; ++i)
821 n_bptr->invars[i] = -1; /* XXX debug */
823 /* pass-through variables enter the block */
825 outer = inner->parent;
826 while (outer != NULL) {
827 depth = outer->n_passthroughcount;
829 assert(depth + inner->n_selfpassthroughcount <= indepth);
831 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
832 varidx = inner->n_passthroughvars[i];
834 inline_new_variable_clone(container->ctx->resultjd,
837 n_bptr->invars[depth + i] = newvaridx;
838 outer->varmap[varidx] = newvaridx;
841 outer = outer->parent;
845 n_bptr->invars = NULL;
848 /* XXX for the verifier. should not be here */
853 dv = DMNEW(varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
854 MZERO(dv, varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
855 n_bptr->inlocals = dv;
862 static s4 *translate_javalocals(inline_node *iln, s4 *javalocals)
867 jl = DMNEW(s4, iln->jd->maxlocals);
869 for (i=0; i<iln->jd->maxlocals; ++i) {
872 j = inline_translate_variable(iln->ctx->resultjd, iln->jd, iln->varmap, j);
877 /* an encoded returnAddress value - must be relocated */
878 inline_add_blocknr_reference(iln, &(jl[i]));
887 static basicblock * create_body_block(inline_node *iln,
888 basicblock *o_bptr, s4 *varmap)
893 n_bptr = create_block(iln, iln, iln,
894 o_bptr->indepth + iln->n_passthroughcount);
896 n_bptr->type = o_bptr->type;
897 n_bptr->flags = o_bptr->flags;
898 n_bptr->bitflags = o_bptr->bitflags;
900 /* resolve references to this block */
902 inline_resolve_block_refs(&(iln->refs), o_bptr, n_bptr, false);
904 /* translate the invars of the original block */
906 for (i=0; i<o_bptr->indepth; ++i) {
907 n_bptr->invars[iln->n_passthroughcount + i] =
908 inline_translate_variable(iln->ctx->resultjd, iln->jd,
913 /* translate javalocals info (not for dead code) */
915 if (n_bptr->flags >= BBREACHED)
916 n_bptr->javalocals = translate_javalocals(iln, o_bptr->javalocals);
922 static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
928 /* number of return variables */
930 retcount = (callee->n_resultlocal == -1
931 && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
933 /* start the epilog block */
935 n_bptr = create_block(caller, caller, callee,
936 callee->n_passthroughcount + retcount);
938 /* resolve references to the return block */
940 inline_resolve_block_refs(&(callee->refs),
941 INLINE_RETURN_REFERENCE(callee),
945 /* return variable */
948 idx = inline_new_variable(caller->ctx->resultjd,
949 callee->m->parseddesc->returntype.type, 0 /* XXX */);
950 n_bptr->invars[callee->n_passthroughcount] = idx;
951 varmap[callee->callerins->dst.varindex] = idx;
956 n_bptr->javalocals = DMNEW(s4, caller->jd->maxlocals);
957 MCOPY(n_bptr->javalocals, caller->javalocals, s4, caller->jd->maxlocals);
959 /* set block flags & type */
961 n_bptr->flags = /* XXX original block flags */ BBFINISHED;
962 n_bptr->type = BBTYPE_STD;
968 static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
975 n_bptr->outdepth = outdepth;
976 n_bptr->outvars = DMNEW(s4, outdepth);
978 for (i=0; i<outdepth; ++i)
979 n_bptr->outvars[i] = 0; /* XXX debug */
981 if (outdepth > iln->ctx->maxinoutdepth)
982 iln->ctx->maxinoutdepth = outdepth;
984 /* pass-through variables leave the block */
986 outer = inner->parent;
987 while (outer != NULL) {
988 depth = outer->n_passthroughcount;
990 assert(depth + inner->n_selfpassthroughcount <= outdepth);
992 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
993 varidx = inner->n_passthroughvars[i];
994 n_bptr->outvars[depth + i] =
995 inline_translate_variable(iln->ctx->resultjd,
1001 outer = outer->parent;
1006 static void close_prolog_block(inline_node *iln,
1008 inline_node *nextcall)
1010 /* XXX add original outvars! */
1011 close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
1013 /* pass-through variables */
1015 DOLOG( printf("closed prolog block:\n");
1016 show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
1020 static void close_body_block(inline_node *iln,
1029 close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
1031 /* translate the outvars of the original block */
1033 /* XXX reuse code */
1034 for (i=0; i<o_bptr->outdepth; ++i) {
1035 n_bptr->outvars[iln->n_passthroughcount + i] =
1036 inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
1037 o_bptr->outvars[i]);
1040 /* set the return variable, if any */
1043 assert(retidx >= 0);
1044 n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
1049 /* inlined code generation ****************************************************/
1051 static instruction * inline_instruction(inline_node *iln,
1053 instruction *o_iptr)
1055 instruction *n_iptr;
1057 n_iptr = (iln->inlined_iinstr_cursor++);
1058 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1060 n_iptr->opc = opcode;
1061 n_iptr->flags.bits = o_iptr->flags.bits & INS_FLAG_ID_MASK;
1062 n_iptr->line = o_iptr->line;
1067 static void inline_generate_sync_builtin(inline_node *iln,
1068 inline_node *callee,
1069 instruction *o_iptr,
1076 if (callee->m->flags & ACC_STATIC) {
1078 syncvar = inline_new_temp_variable(iln->ctx->resultjd, TYPE_ADR);
1080 n_ins = inline_instruction(iln, ICMD_ACONST, o_iptr);
1081 n_ins->sx.val.c.cls = callee->m->class;
1082 n_ins->dst.varindex = syncvar;
1083 n_ins->flags.bits |= INS_FLAG_CLASS;
1086 syncvar = instancevar;
1089 assert(syncvar != UNUSED);
1091 /* MONITORENTER / MONITOREXIT */
1093 n_ins = inline_instruction(iln, ICMD_BUILTIN, o_iptr);
1094 n_ins->sx.s23.s3.bte = builtintable_get_internal(func);
1095 n_ins->s1.argcount = 1; /* XXX add through-vars */
1096 n_ins->sx.s23.s2.args = DMNEW(s4, 1);
1097 n_ins->sx.s23.s2.args[0] = syncvar;
1100 static s4 emit_inlining_prolog(inline_node *iln,
1101 inline_node *callee,
1102 instruction *o_iptr,
1105 methodinfo *calleem;
1111 insinfo_inline *insinfo;
1114 assert(iln && callee && o_iptr);
1116 calleem = callee->m;
1117 md = calleem->parseddesc;
1119 /* INLINE_START instruction */
1121 n_ins = inline_instruction(iln, ICMD_INLINE_START, o_iptr);
1123 insinfo = DNEW(insinfo_inline);
1124 insinfo->method = callee->m;
1125 insinfo->outer = iln->m;
1126 insinfo->synclocal = callee->synclocal;
1127 insinfo->synchronize = callee->synchronize;
1128 insinfo->javalocals_start = NULL;
1129 insinfo->javalocals_end = NULL;
1131 /* info about stack vars live at the INLINE_START */
1133 insinfo->throughcount = callee->n_passthroughcount;
1134 insinfo->paramcount = md->paramcount;
1135 insinfo->stackvarscount = o_iptr->s1.argcount;
1136 insinfo->stackvars = DMNEW(s4, insinfo->stackvarscount);
1137 for (i=0; i<insinfo->stackvarscount; ++i)
1138 insinfo->stackvars[i] = iln->varmap[o_iptr->sx.s23.s2.args[i]];
1140 /* info about the surrounding inlining */
1142 if (iln->inline_start_instruction)
1143 insinfo->parent = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
1145 insinfo->parent = NULL;
1147 /* finish the INLINE_START instruction */
1149 n_ins->sx.s23.s3.inlineinfo = insinfo;
1150 callee->inline_start_instruction = n_ins;
1152 DOLOG( printf("%sprolog: ", iln->indent);
1153 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1155 /* handle parameters for the inlined callee */
1157 localindex = callee->localsoffset + md->paramslots;
1159 for (i=md->paramcount-1; i>=0; --i) {
1162 type = md->paramtypes[i].type;
1164 localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
1165 assert(callee->regdata);
1167 /* translate the argument variable */
1169 varindex = varmap[o_iptr->sx.s23.s2.args[i]];
1170 assert(varindex != UNUSED);
1172 /* remove preallocation from the argument variable */
1174 iln->ctx->resultjd->var[varindex].flags &= ~(PREALLOC | INMEMORY);
1176 /* check the instance slot against NULL */
1177 /* we don't need that for <init> methods, as the verifier */
1178 /* ensures that they are only called for an uninit. object */
1179 /* (which may not be NULL). */
1181 if (!callee->isstatic && i == 0 && calleem->name != utf_init) {
1182 assert(type == TYPE_ADR);
1183 n_ins = inline_instruction(iln, ICMD_CHECKNULL, o_iptr);
1184 n_ins->s1.varindex = varindex;
1185 n_ins->dst.varindex = n_ins->s1.varindex;
1188 /* store argument into local variable of inlined callee */
1190 if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != UNUSED)
1192 /* this value is used in the callee */
1194 if (i == 0 && callee->synclocal != UNUSED) {
1195 /* we also need it for synchronization, so copy it */
1196 assert(type == TYPE_ADR);
1197 n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
1200 n_ins = inline_instruction(iln, ICMD_ISTORE + type, o_iptr);
1201 n_ins->sx.s23.s3.javaindex = UNUSED;
1203 n_ins->s1.varindex = varindex;
1204 n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
1205 assert(n_ins->dst.varindex != UNUSED);
1207 else if (i == 0 && callee->synclocal != UNUSED) {
1208 /* the value is not used inside the callee, but we need it for */
1209 /* synchronization */
1210 /* XXX In this case it actually makes no sense to create a */
1211 /* separate synchronization variable. */
1213 n_ins = inline_instruction(iln, ICMD_NOP, o_iptr);
1216 /* this value is not used, pop it */
1218 n_ins = inline_instruction(iln, ICMD_POP, o_iptr);
1219 n_ins->s1.varindex = varindex;
1222 DOLOG( printf("%sprolog: ", iln->indent);
1223 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1226 /* COPY for synchronized instance methods */
1228 if (callee->synclocal != UNUSED) {
1229 n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
1230 n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
1231 n_ins->dst.varindex = callee->synclocal;
1233 assert(n_ins->s1.varindex != UNUSED);
1236 if (callee->synchronize) {
1237 inline_generate_sync_builtin(iln, callee, o_iptr,
1238 (callee->isstatic) ? UNUSED : varmap[o_iptr->sx.s23.s2.args[0]],
1239 LOCK_monitor_enter);
1242 /* INLINE_BODY instruction */
1244 n_ins = inline_instruction(iln, ICMD_INLINE_BODY, callee->jd->basicblocks[0].iinstr);
1245 n_ins->sx.s23.s3.inlineinfo = insinfo;
1251 static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
1256 assert(iln && callee && o_iptr);
1257 assert(callee->inline_start_instruction);
1259 if (callee->synchronize) {
1260 inline_generate_sync_builtin(iln, callee, o_iptr,
1265 /* INLINE_END instruction */
1267 n_ins = inline_instruction(iln, ICMD_INLINE_END, o_iptr);
1268 n_ins->sx.s23.s3.inlineinfo = callee->inline_start_instruction->sx.s23.s3.inlineinfo;
1270 /* set the javalocals */
1272 jl = DMNEW(s4, iln->jd->maxlocals);
1273 MCOPY(jl, iln->javalocals, s4, iln->jd->maxlocals);
1274 n_ins->sx.s23.s3.inlineinfo->javalocals_end = jl;
1276 DOLOG( printf("%sepilog: ", iln->indent);
1277 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1281 #define TRANSLATE_VAROP(vo) \
1282 n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
1285 static void inline_clone_instruction(inline_node *iln,
1289 instruction *o_iptr,
1290 instruction *n_iptr)
1292 icmdtable_entry_t *icmdt;
1293 builtintable_entry *bte;
1296 branch_target_t *table;
1297 lookup_target_t *lookup;
1302 icmdt = &(icmd_table[o_iptr->opc]);
1304 switch (icmdt->dataflow) {
1309 TRANSLATE_VAROP(sx.s23.s3);
1311 TRANSLATE_VAROP(sx.s23.s2);
1313 TRANSLATE_VAROP(s1);
1317 TRANSLATE_VAROP(sx.s23.s2);
1321 TRANSLATE_VAROP(s1);
1323 TRANSLATE_VAROP(dst);
1327 n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1328 for (i=0; i<n_iptr->s1.argcount; ++i) {
1329 n_iptr->sx.s23.s2.args[i] =
1330 inline_translate_variable(jd, origjd, varmap,
1331 o_iptr->sx.s23.s2.args[i]);
1333 TRANSLATE_VAROP(dst);
1337 INSTRUCTION_GET_METHODDESC(n_iptr, md);
1339 n_iptr->s1.argcount += iln->n_passthroughcount;
1340 n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1341 for (i=0; i<o_iptr->s1.argcount; ++i) {
1342 n_iptr->sx.s23.s2.args[i] =
1343 inline_translate_variable(jd, origjd, varmap,
1344 o_iptr->sx.s23.s2.args[i]);
1346 for (scope = iln; scope != NULL; scope = scope->parent) {
1347 for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
1348 n_iptr->sx.s23.s2.args[i++] =
1349 scope->parent->varmap[scope->n_passthroughvars[j]];
1352 if (md->returntype.type != TYPE_VOID)
1353 TRANSLATE_VAROP(dst);
1357 bte = n_iptr->sx.s23.s3.bte;
1365 switch (icmdt->controlflow) {
1367 TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
1371 inline_add_block_reference(iln, &(n_iptr->dst.block));
1375 inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
1379 i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
1381 table = DMNEW(branch_target_t, i);
1382 MCOPY(table, o_iptr->dst.table, branch_target_t, i);
1383 n_iptr->dst.table = table;
1386 inline_add_block_reference(iln, &(table->block));
1392 inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
1394 i = n_iptr->sx.s23.s2.lookupcount;
1395 lookup = DMNEW(lookup_target_t, i);
1396 MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
1397 n_iptr->dst.lookup = lookup;
1400 inline_add_block_reference(iln, &(lookup->target.block));
1406 /* XXX move this to dataflow section? */
1408 switch (n_iptr->opc) {
1411 if (n_iptr->flags.bits & INS_FLAG_RETADDR)
1412 inline_add_blocknr_reference(iln, &(n_iptr->sx.s23.s2.retaddrnr));
1419 stack_javalocals_store(n_iptr, iln->javalocals);
1425 static void inline_rewrite_method(inline_node *iln)
1429 instruction *o_iptr;
1430 instruction *n_iptr;
1431 inline_node *nextcall;
1433 inline_block_map *bm;
1438 char indent[100]; /* XXX debug */
1444 resultjd = iln->ctx->resultjd;
1448 nextcall = iln->children;
1451 for (i=0; i<iln->depth; ++i)
1454 iln->indent = indent;
1456 DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
1457 printf("%s(passthrough: %d+%d)\n",
1458 indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
1459 iln->n_passthroughcount); );
1461 /* set memory cursors */
1463 iln->inlined_iinstr_cursor = iln->inlined_iinstr;
1464 iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
1466 /* allocate temporary buffers */
1468 iln->javalocals = DMNEW(s4, iln->jd->maxlocals);
1470 /* loop over basic blocks */
1472 o_bptr = iln->jd->basicblocks;
1473 for (; o_bptr; o_bptr = o_bptr->next) {
1475 if (o_bptr->flags < BBREACHED) {
1477 /* ignore the dummy end block */
1479 if (o_bptr->icount == 0 && o_bptr->next == NULL) {
1480 /* enter the following block as translation, for exception handler ranges */
1481 inline_block_translation(iln, o_bptr, iln->inlined_basicblocks_cursor);
1486 printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
1488 o_bptr->nr, o_bptr->flags, o_bptr->type,
1490 method_println(iln->m);
1493 n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1495 /* enter it in the blockmap */
1497 inline_block_translation(iln, o_bptr, n_bptr);
1499 close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
1503 len = o_bptr->icount;
1504 o_iptr = o_bptr->iinstr;
1507 printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
1509 o_bptr->nr, o_bptr->flags, o_bptr->type,
1511 method_println(iln->m);
1512 show_basicblock(iln->jd, o_bptr, SHOW_STACK);
1515 if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
1516 /* create an inlined clone of this block */
1518 n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1521 /* enter it in the blockmap */
1523 inline_block_translation(iln, o_bptr, n_bptr);
1525 /* initialize the javalocals */
1527 MCOPY(iln->javalocals, n_bptr->javalocals, s4, iln->jd->maxlocals);
1532 /* continue caller block */
1534 n_bptr = iln->inlined_basicblocks_cursor - 1;
1535 icount = n_bptr->icount;
1537 /* translate the javalocals */
1539 jl = translate_javalocals(iln, o_bptr->javalocals);
1540 iln->inline_start_instruction->sx.s23.s3.inlineinfo->javalocals_start = jl;
1542 MCOPY(iln->javalocals, jl, s4, iln->jd->maxlocals);
1545 /* iterate over the ICMDs of this block */
1550 while (--len >= 0) {
1552 DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false, SHOW_STACK);
1555 /* handle calls that will be inlined */
1557 if (nextcall && o_iptr == nextcall->callerins) {
1559 /* write the inlining prolog */
1561 (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
1562 icount += nextcall->prolog_instructioncount;
1564 /* end current block, or glue blocks together */
1566 n_bptr->icount = icount;
1568 if (nextcall->blockbefore) {
1569 close_prolog_block(iln, n_bptr, nextcall);
1575 /* check if the result is a local variable */
1577 if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
1578 && o_iptr->dst.varindex < iln->jd->localcount)
1580 nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
1583 nextcall->n_resultlocal = -1;
1585 /* set memory pointers in the callee */
1587 nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
1588 nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
1592 DOLOG( printf("%sentering inline ", indent);
1593 show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1595 inline_rewrite_method(nextcall);
1597 DOLOG( printf("%sleaving inline ", indent);
1598 show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1600 /* update memory cursors */
1602 assert(nextcall->inlined_iinstr_cursor
1603 <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
1604 assert(nextcall->inlined_basicblocks_cursor
1605 == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
1606 iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
1607 iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
1609 /* start new block, or glue blocks together */
1611 if (nextcall->blockafter) {
1612 n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
1616 n_bptr = iln->inlined_basicblocks_cursor - 1;
1617 icount = n_bptr->icount;
1621 /* emit inlining epilog */
1623 emit_inlining_epilog(iln, nextcall, o_iptr);
1624 icount += nextcall->epilog_instructioncount;
1626 /* proceed to next call */
1628 nextcall = nextcall->next;
1631 n_iptr = (iln->inlined_iinstr_cursor++);
1632 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1634 switch (o_iptr->opc) {
1636 if (iln->depth == 0)
1645 if (iln->depth == 0)
1648 retidx = iln->varmap[o_iptr->s1.varindex];
1649 if (iln->n_resultlocal != -1) {
1650 /* store result in a local variable */
1652 DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
1653 /* This relies on the same sequence of types for */
1654 /* ?STORE and ?RETURN opcodes. */
1655 n_iptr->opc = ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN);
1656 n_iptr->s1.varindex = retidx;
1657 n_iptr->dst.varindex = iln->n_resultlocal;
1658 n_iptr->sx.s23.s3.javaindex = UNUSED; /* XXX set real javaindex? */
1663 n_iptr = (iln->inlined_iinstr_cursor++);
1664 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1667 else if ((retidx < resultjd->localcount && iln->blockafter)
1668 || !iln->blockafter) /* XXX do we really always need the MOVE? */
1670 /* local must not become outvar, insert a MOVE */
1672 n_iptr->opc = ICMD_MOVE;
1673 n_iptr->s1.varindex = retidx;
1674 retidx = inline_new_temp_variable(resultjd,
1675 resultjd->var[retidx].type);
1676 n_iptr->dst.varindex = retidx;
1678 n_iptr = (iln->inlined_iinstr_cursor++);
1679 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1683 if (iln->blockafter) {
1684 n_iptr->opc = ICMD_GOTO;
1685 n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
1686 inline_add_block_reference(iln, &(n_iptr->dst.block));
1689 n_iptr->opc = ICMD_NOP;
1693 if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
1694 n_iptr->opc = ICMD_NOP;
1703 inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
1706 DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
1715 /* end of basic block */
1717 if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
1718 close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
1719 n_bptr->icount = icount;
1721 DOLOG( printf("closed body block:\n");
1722 show_basicblock(resultjd, n_bptr, SHOW_STACK); );
1725 n_bptr->icount = icount;
1726 assert(iln->parent);
1727 if (retidx != UNUSED)
1728 iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
1732 bm = iln->ctx->blockmap;
1733 for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
1734 assert(bm->iln && bm->o_block && bm->n_block);
1736 inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block, false);
1739 #if !defined(NDEBUG)
1741 inline_target_ref *ref;
1744 if (!iln->depth || ref->isnumber || *(ref->ref.block) != INLINE_RETURN_REFERENCE(iln)) {
1745 DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
1746 (void*)*(ref->ref.block)) );
1756 static exception_entry * inline_exception_tables(inline_node *iln,
1757 exception_entry *n_extable,
1758 exception_entry **prevextable)
1762 exception_entry *et;
1766 assert(prevextable);
1768 child = iln->children;
1771 n_extable = inline_exception_tables(child, n_extable, prevextable);
1772 child = child->next;
1773 } while (child != iln->children);
1776 et = iln->jd->exceptiontable;
1777 for (; et != NULL; et = et->down) {
1779 MZERO(n_extable, exception_entry, 1);
1780 n_extable->start = inline_map_block(iln, et->start , iln);
1781 n_extable->end = inline_map_block(iln, et->end , iln);
1782 n_extable->handler = inline_map_block(iln, et->handler, iln);
1783 n_extable->catchtype = et->catchtype;
1786 (*prevextable)->down = n_extable;
1788 *prevextable = n_extable;
1793 if (iln->handler_monitorexit) {
1794 exception_entry **activehandlers;
1796 MZERO(n_extable, exception_entry, 1);
1797 n_extable->start = iln->inlined_basicblocks;
1798 n_extable->end = iln->inlined_basicblocks_cursor;
1799 n_extable->handler = iln->handler_monitorexit;
1800 n_extable->catchtype.any = NULL; /* finally */
1803 (*prevextable)->down = n_extable;
1805 *prevextable = n_extable;
1809 /* We have to protect the created handler with the same handlers */
1810 /* that protect the method body itself. */
1812 for (scope = iln; scope->parent != NULL; scope = scope->parent) {
1814 activehandlers = scope->o_handlers;
1815 assert(activehandlers);
1817 while (*activehandlers) {
1819 assert(scope->parent);
1821 MZERO(n_extable, exception_entry, 1);
1822 n_extable->start = iln->handler_monitorexit;
1823 n_extable->end = iln->handler_monitorexit + 1; /* XXX ok in this case? */
1824 n_extable->handler = inline_map_block(scope->parent,
1825 (*activehandlers)->handler,
1827 n_extable->catchtype = (*activehandlers)->catchtype;
1830 (*prevextable)->down = n_extable;
1832 *prevextable = n_extable;
1844 static void inline_locals(inline_node *iln)
1850 iln->varmap = create_variable_map(iln);
1852 child = iln->children;
1855 inline_locals(child);
1856 child = child->next;
1857 } while (child != iln->children);
1860 if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
1861 iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
1862 if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
1863 iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
1864 if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
1865 iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
1869 static void inline_interface_variables(inline_node *iln)
1876 resultjd = iln->ctx->resultjd;
1878 resultjd->interface_map = DMNEW(interface_info, 5*iln->ctx->maxinoutdepth);
1879 for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
1880 resultjd->interface_map[i].flags = UNUSED;
1882 for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
1883 assert(bptr->indepth <= iln->ctx->maxinoutdepth);
1884 assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
1886 for (i=0; i<bptr->indepth; ++i) {
1887 v = &(resultjd->var[bptr->invars[i]]);
1889 if (v->type == TYPE_RET)
1890 v->flags |= PREALLOC;
1892 v->flags &= ~PREALLOC;
1893 v->flags &= ~INMEMORY;
1894 assert(bptr->invars[i] >= resultjd->localcount);
1896 if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1897 resultjd->interface_map[5*i + v->type].flags = v->flags;
1900 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1904 for (i=0; i<bptr->outdepth; ++i) {
1905 v = &(resultjd->var[bptr->outvars[i]]);
1907 if (v->type == TYPE_RET)
1908 v->flags |= PREALLOC;
1910 v->flags &= ~PREALLOC;
1911 v->flags &= ~INMEMORY;
1912 assert(bptr->outvars[i] >= resultjd->localcount);
1914 if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1915 resultjd->interface_map[5*i + v->type].flags = v->flags;
1918 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1925 static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
1930 builtintable_entry *bte;
1935 child = iln->children;
1938 inline_write_exception_handlers(master, child);
1939 child = child->next;
1940 } while (child != iln->children);
1943 if (iln->synchronize) {
1944 /* create the monitorexit handler */
1945 n_bptr = create_block(master, iln, iln,
1946 iln->n_passthroughcount + 1);
1947 n_bptr->type = BBTYPE_EXH;
1948 n_bptr->flags = BBFINISHED;
1950 exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1951 n_bptr->invars[iln->n_passthroughcount] = exvar;
1953 iln->handler_monitorexit = n_bptr;
1955 /* ACONST / ALOAD */
1957 n_ins = master->inlined_iinstr_cursor++;
1958 if (iln->m->flags & ACC_STATIC) {
1959 n_ins->opc = ICMD_ACONST;
1960 n_ins->sx.val.c.cls = iln->m->class;
1961 n_ins->flags.bits = INS_FLAG_CLASS;
1964 n_ins->opc = ICMD_ALOAD;
1965 n_ins->s1.varindex = iln->synclocal;
1966 assert(n_ins->s1.varindex != UNUSED);
1968 /* XXX could be PREALLOCed for builtin call */
1969 syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1970 n_ins->dst.varindex = syncvar;
1975 bte = builtintable_get_internal(LOCK_monitor_exit);
1977 n_ins = master->inlined_iinstr_cursor++;
1978 n_ins->opc = ICMD_BUILTIN;
1979 n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
1980 n_ins->sx.s23.s2.args = DMNEW(s4, n_ins->s1.argcount);
1981 n_ins->sx.s23.s2.args[0] = syncvar;
1982 for (i=0; i < iln->n_passthroughcount + 1; ++i) {
1983 n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
1985 n_ins->sx.s23.s3.bte = bte;
1990 n_ins = master->inlined_iinstr_cursor++;
1991 n_ins->opc = ICMD_ATHROW;
1992 n_ins->flags.bits = 0;
1993 n_ins->s1.varindex = exvar;
1996 /* close basic block */
1998 close_block(iln, iln, n_bptr, iln->n_passthroughcount);
2004 /* second pass driver *********************************************************/
2006 static bool inline_transform(inline_node *iln, jitdata *jd)
2011 exception_entry *n_ext;
2012 exception_entry *prevext;
2016 #if defined(INLINE_VERIFY_RESULT)
2017 static int debug_verify_inlined_code = 1;
2019 #if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
2020 static int debug_counter = 0;
2023 DOLOG( dump_inline_tree(iln, 0); );
2027 n_ins = DMNEW(instruction, iln->cumul_instructioncount);
2028 MZERO(n_ins, instruction, iln->cumul_instructioncount);
2029 iln->inlined_iinstr = n_ins;
2031 n_bb = DMNEW(basicblock, iln->cumul_basicblockcount);
2032 MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
2033 iln->inlined_basicblocks = n_bb;
2035 iln->ctx->blockmap = DMNEW(inline_block_map, iln->cumul_blockmapcount);
2037 n_jd = jit_jitdata_new(iln->m);
2038 n_jd->flags = jd->flags;
2039 n_jd->code->optlevel = jd->code->optlevel;
2040 iln->ctx->resultjd = n_jd;
2044 /* create the local_map */
2046 n_jd->local_map = DMNEW(s4, 5*iln->cumul_maxlocals);
2047 for (i=0; i<5*iln->cumul_maxlocals; ++i)
2048 n_jd->local_map[i] = UNUSED;
2050 /* create / coalesce local variables */
2058 n_jd->localcount = n_jd->vartop;
2060 /* extra variables for verification (debugging) */
2062 #if defined(INLINE_VERIFY_RESULT)
2063 if (debug_verify_inlined_code) {
2064 n_jd->vartop += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
2065 if (n_jd->vartop > n_jd->varcount) {
2067 n_jd->var = DMREALLOC(n_jd->var, varinfo, n_jd->varcount, n_jd->vartop);
2068 n_jd->varcount = n_jd->vartop;
2071 #endif /* defined(INLINE_VERIFY_RESULT) */
2073 /* write inlined code */
2075 inline_rewrite_method(iln);
2077 /* create exception handlers */
2079 inline_write_exception_handlers(iln, iln);
2081 /* write the dummy end block */
2083 n_bptr = create_block(iln, iln, iln, 0);
2084 n_bptr->flags = BBUNDEF;
2085 n_bptr->type = BBTYPE_STD;
2087 /* store created code in jitdata */
2089 n_jd->basicblocks = iln->inlined_basicblocks;
2090 n_jd->instructioncount = iln->cumul_instructioncount;
2091 n_jd->instructions = iln->inlined_iinstr;
2093 /* link the basic blocks (dummy end block is not counted) */
2095 n_jd->basicblockcount = (iln->inlined_basicblocks_cursor - iln->inlined_basicblocks) - 1;
2096 for (i=0; i<n_jd->basicblockcount + 1; ++i)
2097 n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
2099 n_jd->basicblocks[i-1].next = NULL;
2101 /* check basicblock numbers */
2103 #if !defined(NDEBUG)
2104 jit_check_basicblock_numbers(n_jd);
2107 /* create the exception table */
2109 if (iln->cumul_exceptiontablelength) {
2110 exception_entry *tableend;
2112 n_ext = DMNEW(exception_entry, iln->cumul_exceptiontablelength);
2114 tableend = inline_exception_tables(iln, n_ext, &prevext);
2115 assert(tableend == n_ext + iln->cumul_exceptiontablelength);
2117 prevext->down = NULL;
2119 n_jd->exceptiontablelength = iln->cumul_exceptiontablelength;
2120 n_jd->exceptiontable = n_ext;
2126 /*******************************************************************************/
2129 memcpy(n_cd, jd->cd, sizeof(codegendata));
2131 n_cd->method = NULL; /* XXX */
2132 n_jd->maxlocals = iln->cumul_maxlocals;
2133 n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
2135 inline_post_process(n_jd);
2137 inline_interface_variables(iln);
2139 /* for debugging, verify the inlined result */
2141 #if defined(INLINE_VERIFY_RESULT)
2142 if (debug_verify_inlined_code) {
2143 debug_verify_inlined_code = 0;
2144 DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
2145 if (!typecheck(n_jd)) {
2146 *exceptionptr = NULL;
2147 DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
2151 DOLOG( printf("VERIFICATION PASSED.\n") );
2153 debug_verify_inlined_code = 1;
2155 #endif /* defined(INLINE_VERIFY_RESULT) */
2157 /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
2159 n_jd->rd->freemem = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
2160 #if defined(HAS_4BYTE_STACKSLOT)
2161 n_jd->rd->freemem_2 = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
2164 #if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
2165 if ( (n_jd->instructioncount >= opt_inline_debug_min_size)
2166 && (n_jd->instructioncount <= opt_inline_debug_max_size))
2168 if (debug_counter <= opt_inline_debug_end_counter)
2169 #endif /* defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG) */
2171 /* install the inlined result */
2173 *jd->code = *n_jd->code;
2174 n_jd->code = jd->code;
2177 /* statistics and logging */
2179 #if !defined(NDEBUG)
2180 inline_stat_roots++;
2183 printf("==== %d.INLINE ==================================================================\n",
2185 printf("\ninline tree:\n");
2186 dump_inline_tree(iln, 0);
2187 n_jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE | JITDATA_FLAG_SHOWDISASSEMBLE;
2188 /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
2189 printf("-------- DONE -----------------------------------------------------------\n");
2195 #if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
2203 /******************************************************************************/
2204 /* FIRST PASS: build inlining tree */
2205 /******************************************************************************/
2208 /* inline_pre_parse_heuristics *************************************************
2210 Perform heuristic checks whether a call site should be inlined.
2211 These checks are evaluated before the callee has been parsed and analysed.
2214 caller...........inlining node of the caller
2215 callee...........the called method
2216 site.............information on the call site
2219 true........consider for inlining
2220 false.......don't inline
2222 *******************************************************************************/
2224 static bool inline_pre_parse_heuristics(const inline_node *caller,
2225 const methodinfo *callee,
2228 #if defined(INLINE_MAX_DEPTH)
2229 if (caller->depth >= INLINE_MAX_DEPTH)
2237 /* inline_post_parse_heuristics ************************************************
2239 Perform heuristic checks whether a call site should be inlined.
2240 These checks are evaluated after the callee has been parsed and analysed.
2243 caller...........inlining node of the caller (const)
2244 callee...........the called method (const)
2247 true........consider for inlining
2248 false.......don't inline
2250 *******************************************************************************/
2252 static bool inline_post_parse_heuristics(const inline_node *caller,
2253 const inline_node *callee)
2259 /* inline_afterwards_heuristics ************************************************
2261 Perform heuristic checks whether a call site should be inlined.
2262 These checks are evaluated after the inlining plan for the callee has
2266 caller...........inlining node of the caller (const)
2267 callee...........the called method (const)
2270 true........consider for inlining
2271 false.......don't inline
2273 *******************************************************************************/
2275 static bool inline_afterwards_heuristics(const inline_node *caller,
2276 const inline_node *callee)
2278 inline_node *cumulator;
2280 #if defined(INLINE_DEPTH_FIRST)
2283 cumulator = caller->ctx->master;
2287 #if defined(INLINE_MAX_BLOCK_EXPANSION)
2288 || (cumulator->cumul_basicblockcount + callee->cumul_basicblockcount
2289 > INLINE_MAX_BLOCK_EXPANSION*caller->ctx->master->jd->basicblockcount)
2291 #if defined(INLINE_MAX_ICMD_EXPANSION)
2292 || (cumulator->cumul_instructioncount + callee->cumul_instructioncount
2293 > INLINE_MAX_ICMD_EXPANSION*caller->ctx->master->jd->instructioncount)
2304 /* inline_is_monomorphic *******************************************************
2306 Check if the given call site can be proven to be monomorphic.
2309 callee...........the called method
2310 call.............the invocation instruction
2313 site->speculative.....flags whether the inlining is speculative
2314 (only defined if return value is true)
2317 true if the call site is (currently) monomorphic,
2318 false if not or unknown
2320 *******************************************************************************/
2322 static bool inline_is_monomorphic(const methodinfo *callee,
2323 const instruction *call,
2326 if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
2327 || call->opc == ICMD_INVOKESPECIAL))
2329 site->speculative = false;
2333 /* XXX search single implementation for abstract monomorphics */
2335 if ((callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED
2337 == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED))
2340 DOLOG( printf("SPECULATIVE INLINE: "); method_println((methodinfo*)callee); );
2341 site->speculative = true;
2347 /* possibly polymorphic call site */
2353 /* inline_can_inline ***********************************************************
2355 Check if inlining of the given call site is possible.
2358 caller...........inlining node of the caller
2359 callee...........the called method
2360 call.............the invocation instruction
2363 site->speculative.....flags whether the inlining is speculative
2364 (only defined if return value is true)
2367 true if inlining is possible, false if not
2369 *******************************************************************************/
2371 static bool inline_can_inline(const inline_node *caller,
2372 const methodinfo *callee,
2373 const instruction *call,
2376 const inline_node *active;
2378 /* cannot inline native methods */
2380 if (callee->flags & ACC_NATIVE)
2383 /* cannot inline possibly polymorphic calls */
2385 if (!inline_is_monomorphic(callee, call, site))
2388 /* cannot inline recursive calls */
2390 for (active = caller; active; active = active->parent) {
2391 if (callee == active->m) {
2392 DOLOG( printf("RECURSIVE!\n") );
2397 /* inlining is possible */
2403 /* inline_create_callee_node ***************************************************
2405 Create an inlining node for the given callee.
2408 caller...........inlining node of the caller (const)
2409 callee...........the called method
2412 the new inlining node
2414 *******************************************************************************/
2416 static inline_node * inline_create_callee_node(const inline_node *caller,
2419 inline_node *cn; /* the callee inline_node */
2421 cn = DNEW(inline_node);
2422 MZERO(cn, inline_node, 1);
2424 cn->depth = caller->depth + 1;
2425 cn->ctx = caller->ctx;
2427 cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
2428 cn->isstatic = (callee->flags & ACC_STATIC);
2434 /* inline_set_callee_properties ************************************************
2436 Set properties of the inlined call site.
2439 caller...........inlining node of the caller (const)
2440 cn...............the called method
2441 site.............info about the call site (const)
2444 *cn..............has the properties set
2446 *******************************************************************************/
2448 static void inline_set_callee_properties(const inline_node *caller,
2450 const inline_site *site)
2456 /* set info about the call site */
2458 cn->callerblock = site->bptr;
2459 cn->callerins = site->iptr;
2460 cn->callerpc = site->pc;
2461 cn->o_handlers = site->handlers;
2462 cn->n_handlercount = caller->n_handlercount + site->nhandlers;
2464 /* determine if we need basic block boundaries before/after */
2466 cn->blockbefore = false;
2467 cn->blockafter = false;
2469 if (cn->jd->branchtoentry)
2470 cn->blockbefore = true;
2472 if (cn->jd->branchtoend)
2473 cn->blockafter = true;
2475 if (cn->jd->returncount > 1)
2476 cn->blockafter = true;
2478 /* XXX make safer and reusable (maybe store last real block) */
2479 for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
2482 if (cn->jd->returnblock != bptr)
2483 cn->blockafter = true;
2485 /* info about the callee */
2487 cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
2488 cn->prolog_instructioncount = cn->m->parseddesc->paramcount + 2;
2489 cn->epilog_instructioncount = 1; /* INLINE_END */
2490 cn->extra_instructioncount = 0;
2492 /* we need a CHECKNULL for instance methods, except for <init> */
2494 if (!cn->isstatic && cn->m->name != utf_init)
2495 cn->prolog_instructioncount += 1;
2497 /* deal with synchronized callees */
2499 if (cn->synchronize) {
2501 builtintable_entry *bte;
2503 /* we need basic block boundaries because of the handler */
2505 cn->blockbefore = true;
2506 cn->blockafter = true;
2508 /* for synchronized static methods */
2509 /* we need an ACONST, MONITORENTER in the prolog */
2510 /* and ACONST, MONITOREXIT in the epilog */
2512 /* for synchronized instance methods */
2513 /* we need an COPY, MONITORENTER in the prolog */
2514 /* and MONITOREXIT in the epilog */
2517 cn->prolog_instructioncount += 2;
2518 cn->epilog_instructioncount += 2;
2521 cn->prolog_instructioncount += 2;
2522 cn->epilog_instructioncount += 1;
2523 cn->localsoffset += 1;
2526 /* and exception handler */
2527 /* ALOAD, builtin_monitorexit, ATHROW */
2529 cn->extra_instructioncount += 3;
2531 /* exception table entries */
2533 cn->extra_exceptiontablelength = 1 + cn->n_handlercount;
2535 /* add exception handler block */
2537 cn->cumul_basicblockcount_root++;
2539 /* we must call the builtins */
2541 bte = builtintable_get_internal(LOCK_monitor_enter);
2543 if (md->memuse > cn->regdata->memuse)
2544 cn->regdata->memuse = md->memuse;
2545 if (md->argintreguse > cn->regdata->argintreguse)
2546 cn->regdata->argintreguse = md->argintreguse;
2548 bte = builtintable_get_internal(LOCK_monitor_exit);
2550 if (md->memuse > cn->regdata->memuse)
2551 cn->regdata->memuse = md->memuse;
2552 if (md->argintreguse > cn->regdata->argintreguse)
2553 cn->regdata->argintreguse = md->argintreguse;
2556 /* determine pass-through variables */
2558 i = site->iptr->s1.argcount - cn->m->parseddesc->paramcount; /* max # of pass-though vars */
2560 cn->n_passthroughvars = DMNEW(s4, i);
2562 for (argi = site->iptr->s1.argcount - 1; argi >= cn->m->parseddesc->paramcount; --argi) {
2563 s4 idx = site->iptr->sx.s23.s2.args[argi];
2564 if (idx >= caller->jd->localcount) {
2565 cn->n_passthroughvars[j] = idx;
2569 DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
2573 cn->n_selfpassthroughcount = j;
2574 cn->n_passthroughcount = caller->n_passthroughcount + cn->n_selfpassthroughcount;
2578 /* inline_cumulate_counters ****************************************************
2580 Cumulate counters after a node has been decided to become inlined.
2583 caller...........inlining node of the caller
2584 callee...........inlining node of the callee (const)
2587 *caller..........gets cumulated values added
2589 *******************************************************************************/
2591 static void inline_cumulate_counters(inline_node *caller,
2592 const inline_node *cn)
2594 caller->cumul_instructioncount += cn->prolog_instructioncount;
2595 caller->cumul_instructioncount += cn->epilog_instructioncount;
2596 caller->cumul_instructioncount += cn->extra_instructioncount;
2597 caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
2599 caller->cumul_basicblockcount += cn->cumul_basicblockcount;
2600 caller->cumul_basicblockcount_root += cn->cumul_basicblockcount_root;
2601 caller->cumul_blockmapcount += cn->cumul_blockmapcount;
2602 caller->cumul_exceptiontablelength += cn->cumul_exceptiontablelength;
2603 caller->cumul_exceptiontablelength += cn->extra_exceptiontablelength;
2605 if (cn->cumul_maxlocals > caller->cumul_maxlocals)
2606 caller->cumul_maxlocals = cn->cumul_maxlocals;
2608 /* XXX extra block after inlined call */
2609 if (cn->blockafter) {
2610 caller->cumul_basicblockcount += 1;
2611 caller->cumul_blockmapcount += 1;
2616 /* inline_analyse_callee *******************************************************
2618 Analyse an inlining candidate callee.
2621 caller...........inlining node of the caller
2622 callee...........the called method
2623 site.............info about the call site
2626 site->inlined....true if the callee has been selected for inlining
2629 the inline node of the callee, or
2630 NULL if an error has occurred (don't use the inlining plan in this case)
2632 *******************************************************************************/
2634 static inline_node * inline_analyse_callee(inline_node *caller,
2638 inline_node *cn; /* the callee inline_node */
2640 /* create an inline tree node */
2642 cn = inline_create_callee_node(caller, callee);
2644 /* get the intermediate representation of the callee */
2646 if (!inline_jit_compile(cn))
2649 /* evaluate heuristics after parsing the callee */
2651 if (!inline_post_parse_heuristics(caller, cn))
2654 /* the call site will be inlined */
2656 site->inlined = true;
2658 /* set info about the call site */
2660 inline_set_callee_properties(caller, cn, site);
2662 /* insert the node into the inline tree */
2664 inline_insert_inline_node(caller, cn);
2666 /* analyse recursively */
2668 if (!inline_analyse_code(cn))
2671 if (!inline_afterwards_heuristics(caller, cn)) {
2672 #if defined(INLINE_CANCEL_ON_THRESHOLD)
2675 inline_remove_inline_node(caller, cn);
2676 caller->ctx->stopped = true;
2677 site->inlined = false;
2682 /* cumulate counters */
2684 #if defined(INLINE_DEPTH_FIRST)
2685 inline_cumulate_counters(caller, cn);
2688 #if defined(INLINE_BREADTH_FIRST)
2690 inline_cumulate_counters(caller, cn);
2691 caller = caller->parent;
2699 /* inline_process_candidate ****************************************************
2701 Process a selected inlining candidate.
2704 cand.............the candidate
2707 true........everything ok
2708 false.......an error has occurred, don't use the plan
2710 *******************************************************************************/
2712 static bool inline_process_candidate(inline_candidate *cand)
2716 cn = inline_analyse_callee(cand->caller,
2723 if (!cand->site.inlined)
2726 /* store assumptions */
2728 if (cand->site.speculative)
2729 method_add_assumption_monomorphic(cand->callee, cand->caller->ctx->master->m);
2735 /* inline_analyse_code *********************************************************
2737 Analyse the intermediate code of the given inlining node.
2740 iln..............the inlining node
2743 *iln.............the inlining plan
2746 true........everything ok
2747 false.......an error has occurred, don't use the plan
2749 *******************************************************************************/
2751 static bool inline_analyse_code(inline_node *iln)
2758 exception_entry **handlers;
2759 exception_entry *ex;
2770 /* initialize cumulative counters */
2772 iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
2773 iln->cumul_exceptiontablelength += mjd->exceptiontablelength;
2775 /* iterate over basic blocks */
2779 for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
2781 /* count the block */
2782 /* ignore dummy end blocks (but count them for the blockmap) */
2784 iln->cumul_blockmapcount++;
2785 if ((bptr != mjd->basicblocks || iln->blockbefore)
2787 (bptr->icount > 0 || bptr->next != NULL))
2788 iln->cumul_basicblockcount++;
2790 /* skip dead code */
2792 if (bptr->flags < BBREACHED)
2795 /* allocate the buffer of active exception handlers */
2796 /* XXX this wastes some memory, but probably it does not matter */
2798 handlers = DMNEW(exception_entry*, mjd->exceptiontablelength + 1);
2800 /* determine the active exception handlers for this block */
2801 /* XXX maybe the handlers of a block should be part of our IR */
2802 /* XXX this should share code with the type checkers */
2804 for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
2805 if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
2806 handlers[nhandlers++] = ex;
2809 handlers[nhandlers] = NULL;
2812 iptr = bptr->iinstr;
2815 iln->cumul_instructioncount += len;
2817 /* iterate over the instructions of the block */
2819 for (; --len >= 0; ++iptr) {
2821 switch (iptr->opc) {
2822 case ICMD_INVOKEVIRTUAL:
2823 case ICMD_INVOKESPECIAL:
2824 case ICMD_INVOKESTATIC:
2825 case ICMD_INVOKEINTERFACE:
2827 if (!INSTRUCTION_IS_UNRESOLVED(iptr) && !iln->ctx->stopped) {
2828 callee = iptr->sx.s23.s3.fmiref->p.method;
2830 if (inline_can_inline(iln, callee, iptr, &site)) {
2831 site.inlined = false;
2834 site.pc = blockendpc - len - 1;
2835 site.handlers = handlers;
2836 site.nhandlers = nhandlers;
2838 if (inline_pre_parse_heuristics(iln, callee, &site)) {
2839 #if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
2840 inline_add_candidate(iln->ctx, iln, callee, &site);
2842 inline_candidate cand;
2844 cand.callee = callee;
2847 if (!inline_process_candidate(&cand))
2861 /* extra ICMD_MOVE may be necessary */
2862 iln->cumul_instructioncount++;
2867 /* end of basic block */
2874 static void inline_cumulate_counters_recursive(inline_node *iln)
2878 child = iln->children;
2881 inline_cumulate_counters_recursive(child);
2882 inline_cumulate_counters(iln, child);
2883 child = child->next;
2884 } while (child != iln->children);
2889 /* inline_make_inlining_plan ***************************************************
2891 Make an inlining plan for the given root node
2894 iln..............the root node
2897 *iln.............the inlining plan
2900 true........everything ok
2901 false.......an error has occurred, don't use the plan
2903 *******************************************************************************/
2905 #if defined(INLINE_KNAPSACK)
2906 static bool inline_make_inlining_plan(inline_node *iln)
2908 inline_candidate *cand;
2909 #if defined(INLINE_COST_BUDGET)
2910 s4 budget = INLINE_COST_BUDGET;
2911 # define BUDGETMEMBER cost
2913 #if defined(INLINE_WEIGHT_BUDGET)
2914 double budget = INLINE_WEIGHT_BUDGET;
2915 # define BUDGETMEMBER weight
2918 inline_analyse_code(iln);
2920 DOLOG( printf("candidates in "); method_println(iln->m);
2921 inline_candidates_println(iln->ctx); );
2923 while ((cand = inline_pick_best_candidate(iln->ctx)) != NULL)
2925 if (cand->BUDGETMEMBER <= budget) {
2926 DOLOG( printf(" picking: "); inline_candidate_println(cand); );
2928 if (!inline_process_candidate(cand))
2931 #if !defined(INLINE_ADD_NEGATIVE_TO_BUDGET)
2932 if (cand->BUDGETMEMBER > 0)
2934 budget -= cand->BUDGETMEMBER;
2938 inline_cumulate_counters_recursive(iln);
2942 #endif /* defined(INLINE_KNAPSACK) */
2945 #if defined(INLINE_DEPTH_FIRST)
2946 static bool inline_make_inlining_plan(inline_node *iln)
2948 return inline_analyse_code(iln);
2950 #endif /* defined(INLINE_DEPTH_FIRST) */
2953 #if defined(INLINE_BREADTH_FIRST)
2954 static bool inline_make_inlining_plan(inline_node *iln)
2956 inline_candidate *cand;
2958 inline_analyse_code(iln);
2960 DOLOG( printf("candidates in "); method_println(iln->m);
2961 inline_candidates_println(iln->ctx); );
2963 while (!iln->ctx->stopped
2964 && (cand = inline_pick_best_candidate(iln->ctx)) != NULL)
2966 DOLOG( printf(" picking: "); inline_candidate_println(cand); );
2968 if (!inline_process_candidate(cand))
2974 #endif /* defined(INLINE_BREADTH_FIRST) */
2977 /* statistics *****************************************************************/
2979 #if defined(INLINE_STATISTICS)
2980 static void inline_gather_statistics_recursive(inline_node *iln)
2984 inline_stat_inlined_nodes++;
2986 if (iln->depth > inline_stat_max_depth)
2987 inline_stat_max_depth++;
2989 child = iln->children;
2992 inline_gather_statistics_recursive(child);
2993 child = child->next;
2994 } while (child != iln->children);
2997 #endif /* defined(INLINE_STATISTICS) */
3000 #if defined(INLINE_STATISTICS)
3001 static void inline_gather_statistics(inline_node *iln)
3003 inline_stat_roots_transformed++;
3005 inline_gather_statistics_recursive(iln);
3007 #endif /* defined(INLINE_STATISTICS) */
3010 /* post processing ************************************************************/
3012 #define POSTPROCESS_SRC(varindex) live[varindex]--
3013 #define POSTPROCESS_DST(varindex) live[varindex]++
3015 #define POSTPROCESS_SRCOP(s) POSTPROCESS_SRC(iptr->s.varindex)
3016 #define POSTPROCESS_DSTOP(d) POSTPROCESS_DST(iptr->d.varindex)
3018 #define MARKSAVED(varindex) jd->var[varindex].flags |= SAVEDVAR
3020 #define MARK_ALL_SAVED \
3022 for (i=0; i<jd->vartop; ++i) \
3027 static void inline_post_process(jitdata *jd)
3033 icmdtable_entry_t *icmdt;
3036 builtintable_entry *bte;
3038 /* reset the SAVEDVAR flag of all variables */
3040 for (i=0; i<jd->vartop; ++i)
3041 jd->var[i].flags &= ~SAVEDVAR;
3043 /* allocate the life counters */
3045 live = DMNEW(s4, jd->vartop);
3046 MZERO(live, s4, jd->vartop);
3048 /* iterate over all basic blocks */
3050 for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
3051 if (bptr->flags < BBREACHED)
3054 /* make invars live */
3056 for (i=0; i<bptr->indepth; ++i)
3057 POSTPROCESS_DST(bptr->invars[i]);
3059 iptr = bptr->iinstr;
3060 iend = iptr + bptr->icount;
3062 for (; iptr < iend; ++iptr) {
3064 icmdt = &(icmd_table[iptr->opc]);
3066 switch (icmdt->dataflow) {
3068 POSTPROCESS_SRCOP(sx.s23.s3);
3070 POSTPROCESS_SRCOP(sx.s23.s2);
3072 POSTPROCESS_SRCOP(s1);
3074 if (icmdt->flags & ICMDTABLE_CALLS) {
3075 jd->isleafmethod = false;
3081 POSTPROCESS_SRCOP(sx.s23.s2);
3084 POSTPROCESS_SRCOP(s1);
3086 if (icmdt->flags & ICMDTABLE_CALLS) {
3087 jd->isleafmethod = false;
3091 POSTPROCESS_DSTOP(dst);
3095 for (i=0; i<iptr->s1.argcount; ++i) {
3096 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
3098 if (icmdt->flags & ICMDTABLE_CALLS) {
3099 jd->isleafmethod = false;
3102 POSTPROCESS_DSTOP(dst);
3106 INSTRUCTION_GET_METHODDESC(iptr, md);
3108 jd->isleafmethod = false;
3109 for (i=0; i<md->paramcount; ++i) {
3110 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
3112 for (; i<iptr->s1.argcount; ++i) {
3113 MARKSAVED(iptr->sx.s23.s2.args[i]);
3115 if (md->returntype.type != TYPE_VOID)
3116 POSTPROCESS_DSTOP(dst);
3120 bte = iptr->sx.s23.s3.bte;
3122 goto post_process_call;
3128 } /* end instruction loop */
3130 /* consume outvars */
3132 for (i=0; i<bptr->outdepth; ++i)
3133 POSTPROCESS_SRC(bptr->outvars[i]);
3135 #if !defined(NDEBUG)
3136 for (i=jd->localcount; i < jd->vartop; ++i)
3137 assert(live[i] == 0);
3140 } /* end basic block loop */
3144 /* inline_create_root_node *****************************************************
3146 Create the root node of the inlining tree.
3149 jd...............the current jitdata of the root method
3152 the root node of the inlining tree
3154 *******************************************************************************/
3156 static inline_node * inline_create_root_node(jitdata *jd)
3160 iln = DNEW(inline_node);
3161 MZERO(iln, inline_node, 1);
3165 iln->regdata = jd->rd;
3167 iln->blockbefore = true;
3168 iln->blockafter = true;
3170 iln->cumul_instructioncount = 0;
3171 iln->cumul_basicblockcount = 1 /* dummy end block */;
3173 /* create inlining context */
3175 iln->ctx = DNEW(inline_context);
3176 MZERO(iln->ctx, inline_context, 1);
3177 iln->ctx->master = iln;
3178 iln->ctx->next_debugnr = 1; /* XXX debug */
3184 /******************************************************************************/
3185 /* MAIN DRIVER FUNCTION */
3186 /******************************************************************************/
3188 bool inline_inline(jitdata *jd)
3192 DOLOG( printf("==== INLINE ==================================================================\n");
3193 show_method(jd, SHOW_STACK); );
3195 #if defined(INLINE_STATISTICS)
3196 inline_stat_roots++;
3199 iln = inline_create_root_node(jd);
3201 if (inline_make_inlining_plan(iln)) {
3203 /* add blocks to the root node */
3205 iln->cumul_basicblockcount += iln->cumul_basicblockcount_root;
3206 iln->cumul_blockmapcount += iln->cumul_basicblockcount_root;
3208 DOLOG( printf("==== INLINE TRANSFORM ========================================================\n"); );
3211 inline_transform(iln, jd);
3213 #if defined(INLINE_STATISTICS)
3214 inline_gather_statistics(iln);
3218 DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
3225 * These are local overrides for various environment variables in Emacs.
3226 * Please do not remove this and leave it at the end of the file, where
3227 * Emacs will automagically detect them.
3228 * ---------------------------------------------------------------------
3231 * indent-tabs-mode: t
3235 * vim:noexpandtab:sw=4:ts=4: