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 7766 2007-04-19 13:24:48Z michi $
39 #include "mm/memory.h"
41 #if defined(ENABLE_THREADS)
42 # include "threads/native/threads.h"
45 #include "toolbox/logging.h"
47 #include "vm/builtin.h"
48 #include "vm/global.h"
49 #include "vm/initialize.h"
51 #include "vm/jit/jit.h"
52 #include "vm/jit/parse.h"
53 #include "vm/jit/reg.h"
54 #include "vm/jit/show.h"
55 #include "vm/jit/stack.h"
57 #include "vm/jit/inline/inline.h"
58 #include "vm/jit/loop/loop.h"
60 #include "vm/jit/verify/typecheck.h"
62 #include "vmcore/class.h"
63 #include "vmcore/method.h"
64 #include "vmcore/options.h"
65 #include "vmcore/statistics.h"
68 /* algorithm tuning constants *************************************************/
70 /* Algorithm Selection */
71 /* Define exactly one of the following three to select the inlining */
74 /*#define INLINE_DEPTH_FIRST*/
75 /*#define INLINE_BREADTH_FIRST*/
76 #define INLINE_KNAPSACK
78 /* Parameters for knapsack heuristics: */
80 #if defined(INLINE_KNAPSACK)
82 #define INLINE_COUNTDOWN_INIT 1000
83 #define INLINE_COST_OFFSET -16
84 #define INLINE_COST_BUDGET 100
85 /*#define INLINE_WEIGHT_BUDGET 5.0*/
86 /*#define INLINE_ADD_NEGATIVE_TO_BUDGET*/
87 /*#define INLINE_MAX_DEPTH 3*/
88 /*#define INLINE_DIVIDE_COST_BY_FREQ */
92 /* Parameters for depth-first heuristics: */
94 #if defined(INLINE_DEPTH_FIRST)
96 #define INLINE_MAX_DEPTH 3
97 #define INLINE_MAX_BLOCK_EXPANSION 10
98 /*#define INLINE_MAX_ICMD_EXPANSION 10*/
99 /*#define INLINE_CANCEL_ON_THRESHOLD*/
103 /* Parameters for breadth-first heuristics: */
105 #if defined(INLINE_BREADTH_FIRST)
107 /*#define INLINE_MAX_BLOCK_EXPANSION 10*/
108 #define INLINE_MAX_ICMD_EXPANSION 5
113 /* debugging ******************************************************************/
116 #define INLINE_VERBOSE
117 #define DOLOG(code) do{ if (opt_inline_debug_log) { code; } }while(0)
122 #if defined(ENABLE_VERIFIER) && !defined(NDEBUG)
123 /* Define this to verify the resulting code after inlining. */
124 /* Note: This is only useful for development and may require patches to the */
126 /* #define INLINE_VERIFY_RESULT */
130 /* types **********************************************************************/
132 typedef struct inline_node inline_node;
133 typedef struct inline_target_ref inline_target_ref;
134 typedef struct inline_context inline_context;
135 typedef struct inline_block_map inline_block_map;
136 typedef struct inline_site inline_site;
137 typedef struct inline_candidate inline_candidate;
144 inline_node *children;
145 inline_node *next; /* next node at this depth */
146 inline_node *prev; /* prev node at this depth */
147 int depth; /* inlining depth, 0 for root */
149 /* info about the call site (if depth > 0)*/
150 inline_node *parent; /* node of the caller (NULL for root) */
151 basicblock *callerblock; /* original block containing the INVOKE* */
152 instruction *callerins; /* the original INVOKE* instruction */
154 s4 *n_passthroughvars;
155 int n_passthroughcount;
156 int n_selfpassthroughcount; /* # of pass-through vars of the call itself */
157 exception_entry **o_handlers;
158 int n_handlercount; /* # of handlers protecting this call */
160 int synclocal; /* variable used for synchr., or UNUSED */
161 bool isstatic; /* this is a static call */
163 bool blockbefore; /* block boundary before inlined body? */
164 bool blockafter; /* block boundary after inlined body? */
166 /* info about the callee */
168 int prolog_instructioncount; /* # of ICMDs in the inlining prolog */
169 int epilog_instructioncount; /* # of ICMDs in the inlining epilog */
170 int extra_instructioncount;
171 int extra_exceptiontablelength; /* # of extra handlers to put in caller */
172 bool synchronize; /* do we have to synchronize enter/exit? */
173 basicblock *handler_monitorexit; /* handler for synchronized inlinees */
176 /* cumulative values */
177 int cumul_instructioncount; /* ICMDs in this node and its children */
178 int cumul_basicblockcount; /* BBs started by this node and its children */
179 int cumul_basicblockcount_root; /* BBs that have to be added to the root */
180 /* node if this node is inlined */
181 int cumul_blockmapcount;
183 int cumul_exceptiontablelength;
186 instruction *inlined_iinstr;
187 instruction *inlined_iinstr_cursor;
188 basicblock *inlined_basicblocks;
189 basicblock *inlined_basicblocks_cursor;
192 registerdata *regdata;
195 inline_target_ref *refs;
196 instruction *inline_start_instruction;
204 struct inline_target_ref {
205 inline_target_ref *next;
214 struct inline_block_map {
220 struct inline_context {
225 inline_candidate *candidates;
227 int next_block_number;
228 inline_block_map *blockmap;
235 int next_debugnr; /* XXX debug */
239 bool speculative; /* true, if inlining would be speculative */
240 bool inlined; /* true, if this site has been inlined */
242 basicblock *bptr; /* basic block containing the call site */
243 instruction *iptr; /* the invocation instruction */
244 exception_entry **handlers; /* active handlers at the call site */
245 s4 nhandlers; /* number of active handlers */
246 s4 pc; /* PC of the invocation instruction */
249 struct inline_candidate {
250 inline_candidate *next;
260 /* prototypes *****************************************************************/
262 static bool inline_analyse_code(inline_node *iln);
263 static void inline_post_process(jitdata *jd);
266 /* debug helpers **************************************************************/
269 #include "inline_debug.inc"
273 /* statistics *****************************************************************/
275 /*#define INLINE_STATISTICS*/
278 #define INLINE_STATISTICS
281 #if defined(INLINE_STATISTICS)
282 int inline_stat_roots = 0;
283 int inline_stat_roots_transformed = 0;
284 int inline_stat_inlined_nodes = 0;
285 int inline_stat_max_depth = 0;
287 void inline_print_stats()
289 printf("inlining statistics:\n");
290 printf(" roots analysed : %d\n", inline_stat_roots);
291 printf(" roots transformed: %d\n", inline_stat_roots_transformed);
292 printf(" inlined nodes : %d\n", inline_stat_inlined_nodes);
293 printf(" max depth : %d\n", inline_stat_max_depth);
298 /* compilation of callees *****************************************************/
300 static bool inline_jit_compile_intern(jitdata *jd)
304 /* XXX should share code with jit.c */
308 /* XXX initialize the static function's class */
312 /* call the compiler passes ***********************************************/
314 /* call parse pass */
316 DOLOG( log_message_class("Parsing ", m->class) );
321 /* call stack analysis pass */
323 if (!stack_analyse(jd)) {
331 static bool inline_jit_compile(inline_node *iln)
337 /* XXX should share code with jit.c */
343 #if defined(ENABLE_THREADS)
344 /* enter a monitor on the method */
345 lock_monitor_enter((java_objectheader *) m);
348 /* allocate jitdata structure and fill it */
350 jd = jit_jitdata_new(m);
353 jd->flags = 0; /* XXX */
355 /* initialize the register allocator */
359 /* setup the codegendata memory */
361 /* XXX do a pseudo setup */
362 jd->cd = DNEW(codegendata);
363 MZERO(jd->cd, codegendata, 1);
365 /* XXX uses too much dump memory codegen_setup(jd); */
367 /* now call internal compile function */
369 r = inline_jit_compile_intern(jd);
372 iln->regdata = jd->rd;
375 /* free some memory */
378 #if defined(ENABLE_JIT)
379 # if defined(ENABLE_INTRP)
387 #if defined(ENABLE_THREADS)
388 /* leave the monitor */
389 lock_monitor_exit((java_objectheader *) m );
396 /* inlining tree handling *****************************************************/
398 static void inline_insert_inline_node(inline_node *parent, inline_node *child)
403 assert(parent && child);
405 child->parent = parent;
407 child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
409 first = parent->children;
411 /* insert as only node */
412 parent->children = child;
418 /* {there is at least one child already there} */
420 /* XXX is this search necessary, or could we always add at the end? */
423 while (succ->callerpc < child->callerpc) {
426 /* insert as last node */
427 child->prev = first->prev;
429 child->prev->next = child;
430 child->next->prev = child;
435 assert(succ->callerpc > child->callerpc);
437 /* insert before succ */
439 child->prev = succ->prev;
441 child->prev->next = child;
442 child->next->prev = child;
444 if (parent->children == succ)
445 parent->children = child;
449 static void inline_remove_inline_node(inline_node *parent, inline_node *child)
453 assert(child->parent == parent);
455 if (child->prev == child) {
456 /* remove the only child node */
457 parent->children = NULL;
460 child->prev->next = child->next;
461 child->next->prev = child->prev;
463 if (parent->children == child)
464 parent->children = child->next;
469 /* inlining candidate handling ************************************************/
471 #if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
472 static void inline_add_candidate(inline_context *ctx,
477 inline_candidate **link;
478 inline_candidate *cand;
480 cand = DNEW(inline_candidate);
481 #if defined(INLINE_DIVIDE_COST_BY_FREQ)
482 cand->freq = INLINE_COUNTDOWN_INIT - callee->hitcountdown;
486 #if defined(INLINE_KNAPSACK)
487 cand->cost = callee->jcodelength + INLINE_COST_OFFSET;
489 #if defined(INLINE_BREADTH_FIRST)
490 cand->cost = caller->depth;
492 cand->caller = caller;
493 cand->callee = callee;
496 cand->weight = (double)cand->cost / cand->freq;
498 for (link = &(ctx->candidates); ; link = &((*link)->next)) {
499 if (!*link || (*link)->weight > cand->weight) {
506 #endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
508 #if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
509 static inline_candidate * inline_pick_best_candidate(inline_context *ctx)
511 inline_candidate *cand;
513 cand = ctx->candidates;
516 ctx->candidates = cand->next;
520 #endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
522 #if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
523 static void inline_candidate_println(inline_candidate *cand)
525 printf("%10g (%5d / %5d) depth %2d ",
526 cand->weight, cand->cost, cand->freq, cand->caller->depth + 1);
527 method_println(cand->callee);
529 #endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
532 #if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
533 static void inline_candidates_println(inline_context *ctx)
535 inline_candidate *cand;
537 for (cand = ctx->candidates; cand != NULL; cand = cand->next) {
539 inline_candidate_println(cand);
542 #endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
545 /* variable handling **********************************************************/
547 static s4 inline_new_variable(jitdata *jd, s4 type, s4 flags)
552 index = jd->vartop++;
553 if (index >= jd->varcount) {
554 newcount = jd->vartop * 2; /* XXX */
555 jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, newcount);
556 MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
557 jd->varcount = newcount;
560 jd->var[index].type = type;
561 jd->var[index].flags = flags;
567 static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
572 v = &(origjd->var[origidx]);
574 newidx = inline_new_variable(jd, v->type, v->flags);
576 jd->var[newidx].vv = v->vv;
582 static s4 inline_new_temp_variable(jitdata *jd, s4 type)
584 return inline_new_variable(jd, type, 0);
588 static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
595 idx = inline_new_variable_clone(jd, origjd, index);
603 static s4 *create_variable_map(inline_node *callee)
612 /* create the variable mapping */
614 varmap = DMNEW(s4, callee->jd->varcount);
615 for (i=0; i<callee->jd->varcount; ++i)
618 /* translate local variables */
620 for (i=0; i<callee->m->maxlocals; ++i) {
621 for (t=0; t<5; ++t) {
622 varindex = callee->jd->local_map[5*i + t];
623 if (varindex == UNUSED)
626 v = &(callee->jd->var[varindex]);
627 assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
628 v->type = t; /* XXX restore if it is TYPE_VOID */
630 avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
632 if (avail == UNUSED) {
633 avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, varindex);
634 callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
637 varmap[varindex] = avail;
641 /* for synchronized instance methods we need an extra local */
643 if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
644 n_javaindex = callee->localsoffset - 1;
645 assert(n_javaindex >= 0);
646 assert(callee->parent);
647 assert(n_javaindex == callee->parent->localsoffset + callee->parent->m->maxlocals);
649 avail = callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR];
651 if (avail == UNUSED) {
652 avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
653 callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR] = avail;
656 callee->synclocal = avail;
659 callee->synclocal = UNUSED;
666 /* basic block translation ****************************************************/
668 #define INLINE_RETURN_REFERENCE(callee) \
669 ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
672 static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
674 inline_target_ref *ref;
676 ref = DNEW(inline_target_ref);
677 ref->ref.block = blockp;
678 ref->isnumber = false;
679 ref->next = iln->refs;
684 static void inline_add_blocknr_reference(inline_node *iln, s4 *nrp)
686 inline_target_ref *ref;
688 ref = DNEW(inline_target_ref);
690 ref->isnumber = true;
691 ref->next = iln->refs;
696 static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
701 assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
703 ctx->blockmap[ctx->blockmap_index].iln = iln;
704 ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
705 ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
707 ctx->blockmap_index++;
711 static basicblock * inline_map_block(inline_node *iln,
713 inline_node *targetiln)
715 inline_block_map *bm;
716 inline_block_map *bmend;
724 bm = iln->ctx->blockmap;
725 bmend = bm + iln->ctx->blockmap_index;
728 assert(bm->iln && bm->o_block && bm->n_block);
729 if (bm->o_block == o_block && bm->iln == targetiln)
735 return NULL; /* not reached */
739 static void inline_resolve_block_refs(inline_target_ref **refs,
744 inline_target_ref *ref;
745 inline_target_ref *prev;
748 for (ref = *refs; ref != NULL; ref = ref->next) {
749 if (ref->isnumber && !returnref) {
750 if (*(ref->ref.nr) == JAVALOCAL_FROM_RETADDR(o_bptr->nr)) {
751 *(ref->ref.nr) = JAVALOCAL_FROM_RETADDR(n_bptr->nr);
756 if (*(ref->ref.block) == o_bptr) {
757 *(ref->ref.block) = n_bptr;
768 /* remove this ref */
771 prev->next = ref->next;
780 /* basic block creation *******************************************************/
782 static basicblock * create_block(inline_node *container,
797 assert(indepth >= 0);
799 n_bptr = container->inlined_basicblocks_cursor++;
801 assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
803 BASICBLOCK_INIT(n_bptr, iln->m);
805 n_bptr->iinstr = container->inlined_iinstr_cursor;
806 n_bptr->next = n_bptr + 1;
807 n_bptr->nr = container->ctx->next_block_number++;
808 n_bptr->indepth = indepth;
809 n_bptr->flags = BBFINISHED; /* XXX */
811 /* set the inlineinfo of the new block */
813 if (iln->inline_start_instruction)
814 n_bptr->inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
816 if (indepth > container->ctx->maxinoutdepth)
817 container->ctx->maxinoutdepth = indepth;
820 n_bptr->invars = DMNEW(s4, indepth);
823 for (i=0; i<indepth; ++i)
824 n_bptr->invars[i] = -1; /* XXX debug */
826 /* pass-through variables enter the block */
828 outer = inner->parent;
829 while (outer != NULL) {
830 depth = outer->n_passthroughcount;
832 assert(depth + inner->n_selfpassthroughcount <= indepth);
834 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
835 varidx = inner->n_passthroughvars[i];
837 inline_new_variable_clone(container->ctx->resultjd,
840 n_bptr->invars[depth + i] = newvaridx;
841 outer->varmap[varidx] = newvaridx;
844 outer = outer->parent;
848 n_bptr->invars = NULL;
851 /* XXX for the verifier. should not be here */
856 dv = DMNEW(varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
857 MZERO(dv, varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
858 n_bptr->inlocals = dv;
865 static s4 *translate_javalocals(inline_node *iln, s4 *javalocals)
870 jl = DMNEW(s4, iln->jd->maxlocals);
872 for (i=0; i<iln->jd->maxlocals; ++i) {
875 j = inline_translate_variable(iln->ctx->resultjd, iln->jd, iln->varmap, j);
880 /* an encoded returnAddress value - must be relocated */
881 inline_add_blocknr_reference(iln, &(jl[i]));
890 static basicblock * create_body_block(inline_node *iln,
891 basicblock *o_bptr, s4 *varmap)
896 n_bptr = create_block(iln, iln, iln,
897 o_bptr->indepth + iln->n_passthroughcount);
899 n_bptr->type = o_bptr->type;
900 n_bptr->flags = o_bptr->flags;
901 n_bptr->bitflags = o_bptr->bitflags;
903 /* resolve references to this block */
905 inline_resolve_block_refs(&(iln->refs), o_bptr, n_bptr, false);
907 /* translate the invars of the original block */
909 for (i=0; i<o_bptr->indepth; ++i) {
910 n_bptr->invars[iln->n_passthroughcount + i] =
911 inline_translate_variable(iln->ctx->resultjd, iln->jd,
916 /* translate javalocals info (not for dead code) */
918 if (n_bptr->flags >= BBREACHED)
919 n_bptr->javalocals = translate_javalocals(iln, o_bptr->javalocals);
925 static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
931 /* number of return variables */
933 retcount = (callee->n_resultlocal == -1
934 && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
936 /* start the epilog block */
938 n_bptr = create_block(caller, caller, callee,
939 callee->n_passthroughcount + retcount);
941 /* resolve references to the return block */
943 inline_resolve_block_refs(&(callee->refs),
944 INLINE_RETURN_REFERENCE(callee),
948 /* return variable */
951 idx = inline_new_variable(caller->ctx->resultjd,
952 callee->m->parseddesc->returntype.type, 0 /* XXX */);
953 n_bptr->invars[callee->n_passthroughcount] = idx;
954 varmap[callee->callerins->dst.varindex] = idx;
959 n_bptr->javalocals = DMNEW(s4, caller->jd->maxlocals);
960 MCOPY(n_bptr->javalocals, caller->javalocals, s4, caller->jd->maxlocals);
962 /* set block flags & type */
964 n_bptr->flags = /* XXX original block flags */ BBFINISHED;
965 n_bptr->type = BBTYPE_STD;
971 static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
978 n_bptr->outdepth = outdepth;
979 n_bptr->outvars = DMNEW(s4, outdepth);
981 for (i=0; i<outdepth; ++i)
982 n_bptr->outvars[i] = 0; /* XXX debug */
984 if (outdepth > iln->ctx->maxinoutdepth)
985 iln->ctx->maxinoutdepth = outdepth;
987 /* pass-through variables leave the block */
989 outer = inner->parent;
990 while (outer != NULL) {
991 depth = outer->n_passthroughcount;
993 assert(depth + inner->n_selfpassthroughcount <= outdepth);
995 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
996 varidx = inner->n_passthroughvars[i];
997 n_bptr->outvars[depth + i] =
998 inline_translate_variable(iln->ctx->resultjd,
1004 outer = outer->parent;
1009 static void close_prolog_block(inline_node *iln,
1011 inline_node *nextcall)
1013 /* XXX add original outvars! */
1014 close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
1016 /* pass-through variables */
1018 DOLOG( printf("closed prolog block:\n");
1019 show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
1023 static void close_body_block(inline_node *iln,
1032 close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
1034 /* translate the outvars of the original block */
1036 /* XXX reuse code */
1037 for (i=0; i<o_bptr->outdepth; ++i) {
1038 n_bptr->outvars[iln->n_passthroughcount + i] =
1039 inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
1040 o_bptr->outvars[i]);
1043 /* set the return variable, if any */
1046 assert(retidx >= 0);
1047 n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
1052 /* inlined code generation ****************************************************/
1054 static instruction * inline_instruction(inline_node *iln,
1056 instruction *o_iptr)
1058 instruction *n_iptr;
1060 n_iptr = (iln->inlined_iinstr_cursor++);
1061 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1063 n_iptr->opc = opcode;
1064 n_iptr->flags.bits = o_iptr->flags.bits & INS_FLAG_ID_MASK;
1065 n_iptr->line = o_iptr->line;
1070 static void inline_generate_sync_builtin(inline_node *iln,
1071 inline_node *callee,
1072 instruction *o_iptr,
1079 if (callee->m->flags & ACC_STATIC) {
1081 syncvar = inline_new_temp_variable(iln->ctx->resultjd, TYPE_ADR);
1083 n_ins = inline_instruction(iln, ICMD_ACONST, o_iptr);
1084 n_ins->sx.val.c.cls = callee->m->class;
1085 n_ins->dst.varindex = syncvar;
1086 n_ins->flags.bits |= INS_FLAG_CLASS;
1089 syncvar = instancevar;
1092 assert(syncvar != UNUSED);
1094 /* MONITORENTER / MONITOREXIT */
1096 n_ins = inline_instruction(iln, ICMD_BUILTIN, o_iptr);
1097 n_ins->sx.s23.s3.bte = builtintable_get_internal(func);
1098 n_ins->s1.argcount = 1; /* XXX add through-vars */
1099 n_ins->sx.s23.s2.args = DMNEW(s4, 1);
1100 n_ins->sx.s23.s2.args[0] = syncvar;
1103 static s4 emit_inlining_prolog(inline_node *iln,
1104 inline_node *callee,
1105 instruction *o_iptr,
1108 methodinfo *calleem;
1114 insinfo_inline *insinfo;
1117 assert(iln && callee && o_iptr);
1119 calleem = callee->m;
1120 md = calleem->parseddesc;
1122 /* INLINE_START instruction */
1124 n_ins = inline_instruction(iln, ICMD_INLINE_START, o_iptr);
1126 insinfo = DNEW(insinfo_inline);
1127 insinfo->method = callee->m;
1128 insinfo->outer = iln->m;
1129 insinfo->synclocal = callee->synclocal;
1130 insinfo->synchronize = callee->synchronize;
1131 insinfo->javalocals_start = NULL;
1132 insinfo->javalocals_end = NULL;
1134 /* info about stack vars live at the INLINE_START */
1136 insinfo->throughcount = callee->n_passthroughcount;
1137 insinfo->paramcount = md->paramcount;
1138 insinfo->stackvarscount = o_iptr->s1.argcount;
1139 insinfo->stackvars = DMNEW(s4, insinfo->stackvarscount);
1140 for (i=0; i<insinfo->stackvarscount; ++i)
1141 insinfo->stackvars[i] = iln->varmap[o_iptr->sx.s23.s2.args[i]];
1143 /* info about the surrounding inlining */
1145 if (iln->inline_start_instruction)
1146 insinfo->parent = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
1148 insinfo->parent = NULL;
1150 /* finish the INLINE_START instruction */
1152 n_ins->sx.s23.s3.inlineinfo = insinfo;
1153 callee->inline_start_instruction = n_ins;
1155 DOLOG( printf("%sprolog: ", iln->indent);
1156 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1158 /* handle parameters for the inlined callee */
1160 localindex = callee->localsoffset + md->paramslots;
1162 for (i=md->paramcount-1; i>=0; --i) {
1165 type = md->paramtypes[i].type;
1167 localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
1168 assert(callee->regdata);
1170 /* translate the argument variable */
1172 varindex = varmap[o_iptr->sx.s23.s2.args[i]];
1173 assert(varindex != UNUSED);
1175 /* remove preallocation from the argument variable */
1177 iln->ctx->resultjd->var[varindex].flags &= ~(PREALLOC | INMEMORY);
1179 /* check the instance slot against NULL */
1180 /* we don't need that for <init> methods, as the verifier */
1181 /* ensures that they are only called for an uninit. object */
1182 /* (which may not be NULL). */
1184 if (!callee->isstatic && i == 0 && calleem->name != utf_init) {
1185 assert(type == TYPE_ADR);
1186 n_ins = inline_instruction(iln, ICMD_CHECKNULL, o_iptr);
1187 n_ins->s1.varindex = varindex;
1188 n_ins->dst.varindex = n_ins->s1.varindex;
1191 /* store argument into local variable of inlined callee */
1193 if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != UNUSED)
1195 /* this value is used in the callee */
1197 if (i == 0 && callee->synclocal != UNUSED) {
1198 /* we also need it for synchronization, so copy it */
1199 assert(type == TYPE_ADR);
1200 n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
1203 n_ins = inline_instruction(iln, ICMD_ISTORE + type, o_iptr);
1204 n_ins->sx.s23.s3.javaindex = UNUSED;
1206 n_ins->s1.varindex = varindex;
1207 n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
1208 assert(n_ins->dst.varindex != UNUSED);
1210 else if (i == 0 && callee->synclocal != UNUSED) {
1211 /* the value is not used inside the callee, but we need it for */
1212 /* synchronization */
1213 /* XXX In this case it actually makes no sense to create a */
1214 /* separate synchronization variable. */
1216 n_ins = inline_instruction(iln, ICMD_NOP, o_iptr);
1219 /* this value is not used, pop it */
1221 n_ins = inline_instruction(iln, ICMD_POP, o_iptr);
1222 n_ins->s1.varindex = varindex;
1225 DOLOG( printf("%sprolog: ", iln->indent);
1226 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1229 /* COPY for synchronized instance methods */
1231 if (callee->synclocal != UNUSED) {
1232 n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
1233 n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
1234 n_ins->dst.varindex = callee->synclocal;
1236 assert(n_ins->s1.varindex != UNUSED);
1239 if (callee->synchronize) {
1240 inline_generate_sync_builtin(iln, callee, o_iptr,
1241 (callee->isstatic) ? UNUSED : varmap[o_iptr->sx.s23.s2.args[0]],
1242 LOCK_monitor_enter);
1245 /* INLINE_BODY instruction */
1247 n_ins = inline_instruction(iln, ICMD_INLINE_BODY, callee->jd->basicblocks[0].iinstr);
1248 n_ins->sx.s23.s3.inlineinfo = insinfo;
1254 static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
1259 assert(iln && callee && o_iptr);
1260 assert(callee->inline_start_instruction);
1262 if (callee->synchronize) {
1263 inline_generate_sync_builtin(iln, callee, o_iptr,
1268 /* INLINE_END instruction */
1270 n_ins = inline_instruction(iln, ICMD_INLINE_END, o_iptr);
1271 n_ins->sx.s23.s3.inlineinfo = callee->inline_start_instruction->sx.s23.s3.inlineinfo;
1273 /* set the javalocals */
1275 jl = DMNEW(s4, iln->jd->maxlocals);
1276 MCOPY(jl, iln->javalocals, s4, iln->jd->maxlocals);
1277 n_ins->sx.s23.s3.inlineinfo->javalocals_end = jl;
1279 DOLOG( printf("%sepilog: ", iln->indent);
1280 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1284 #define TRANSLATE_VAROP(vo) \
1285 n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
1288 static void inline_clone_instruction(inline_node *iln,
1292 instruction *o_iptr,
1293 instruction *n_iptr)
1295 icmdtable_entry_t *icmdt;
1296 builtintable_entry *bte;
1299 branch_target_t *table;
1300 lookup_target_t *lookup;
1305 icmdt = &(icmd_table[o_iptr->opc]);
1307 switch (icmdt->dataflow) {
1312 TRANSLATE_VAROP(sx.s23.s3);
1314 TRANSLATE_VAROP(sx.s23.s2);
1316 TRANSLATE_VAROP(s1);
1320 TRANSLATE_VAROP(sx.s23.s2);
1324 TRANSLATE_VAROP(s1);
1326 TRANSLATE_VAROP(dst);
1330 n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1331 for (i=0; i<n_iptr->s1.argcount; ++i) {
1332 n_iptr->sx.s23.s2.args[i] =
1333 inline_translate_variable(jd, origjd, varmap,
1334 o_iptr->sx.s23.s2.args[i]);
1336 TRANSLATE_VAROP(dst);
1340 INSTRUCTION_GET_METHODDESC(n_iptr, md);
1342 n_iptr->s1.argcount += iln->n_passthroughcount;
1343 n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1344 for (i=0; i<o_iptr->s1.argcount; ++i) {
1345 n_iptr->sx.s23.s2.args[i] =
1346 inline_translate_variable(jd, origjd, varmap,
1347 o_iptr->sx.s23.s2.args[i]);
1349 for (scope = iln; scope != NULL; scope = scope->parent) {
1350 for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
1351 n_iptr->sx.s23.s2.args[i++] =
1352 scope->parent->varmap[scope->n_passthroughvars[j]];
1355 if (md->returntype.type != TYPE_VOID)
1356 TRANSLATE_VAROP(dst);
1360 bte = n_iptr->sx.s23.s3.bte;
1368 switch (icmdt->controlflow) {
1370 TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
1374 inline_add_block_reference(iln, &(n_iptr->dst.block));
1378 inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
1382 i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
1384 table = DMNEW(branch_target_t, i);
1385 MCOPY(table, o_iptr->dst.table, branch_target_t, i);
1386 n_iptr->dst.table = table;
1389 inline_add_block_reference(iln, &(table->block));
1395 inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
1397 i = n_iptr->sx.s23.s2.lookupcount;
1398 lookup = DMNEW(lookup_target_t, i);
1399 MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
1400 n_iptr->dst.lookup = lookup;
1403 inline_add_block_reference(iln, &(lookup->target.block));
1409 /* XXX move this to dataflow section? */
1411 switch (n_iptr->opc) {
1414 if (n_iptr->flags.bits & INS_FLAG_RETADDR)
1415 inline_add_blocknr_reference(iln, &(n_iptr->sx.s23.s2.retaddrnr));
1422 stack_javalocals_store(n_iptr, iln->javalocals);
1428 static void inline_rewrite_method(inline_node *iln)
1432 instruction *o_iptr;
1433 instruction *n_iptr;
1434 inline_node *nextcall;
1436 inline_block_map *bm;
1441 char indent[100]; /* XXX debug */
1447 resultjd = iln->ctx->resultjd;
1451 nextcall = iln->children;
1454 for (i=0; i<iln->depth; ++i)
1457 iln->indent = indent;
1459 DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
1460 printf("%s(passthrough: %d+%d)\n",
1461 indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
1462 iln->n_passthroughcount); );
1464 /* set memory cursors */
1466 iln->inlined_iinstr_cursor = iln->inlined_iinstr;
1467 iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
1469 /* allocate temporary buffers */
1471 iln->javalocals = DMNEW(s4, iln->jd->maxlocals);
1473 /* loop over basic blocks */
1475 o_bptr = iln->jd->basicblocks;
1476 for (; o_bptr; o_bptr = o_bptr->next) {
1478 if (o_bptr->flags < BBREACHED) {
1480 /* ignore the dummy end block */
1482 if (o_bptr->icount == 0 && o_bptr->next == NULL) {
1483 /* enter the following block as translation, for exception handler ranges */
1484 inline_block_translation(iln, o_bptr, iln->inlined_basicblocks_cursor);
1489 printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
1491 o_bptr->nr, o_bptr->flags, o_bptr->type,
1493 method_println(iln->m);
1496 n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1498 /* enter it in the blockmap */
1500 inline_block_translation(iln, o_bptr, n_bptr);
1502 close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
1506 len = o_bptr->icount;
1507 o_iptr = o_bptr->iinstr;
1510 printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
1512 o_bptr->nr, o_bptr->flags, o_bptr->type,
1514 method_println(iln->m);
1515 show_basicblock(iln->jd, o_bptr, SHOW_STACK);
1518 if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
1519 /* create an inlined clone of this block */
1521 n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1524 /* enter it in the blockmap */
1526 inline_block_translation(iln, o_bptr, n_bptr);
1528 /* initialize the javalocals */
1530 MCOPY(iln->javalocals, n_bptr->javalocals, s4, iln->jd->maxlocals);
1535 /* continue caller block */
1537 n_bptr = iln->inlined_basicblocks_cursor - 1;
1538 icount = n_bptr->icount;
1540 /* translate the javalocals */
1542 jl = translate_javalocals(iln, o_bptr->javalocals);
1543 iln->inline_start_instruction->sx.s23.s3.inlineinfo->javalocals_start = jl;
1545 MCOPY(iln->javalocals, jl, s4, iln->jd->maxlocals);
1548 /* iterate over the ICMDs of this block */
1553 while (--len >= 0) {
1555 DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false, SHOW_STACK);
1558 /* handle calls that will be inlined */
1560 if (nextcall && o_iptr == nextcall->callerins) {
1562 /* write the inlining prolog */
1564 (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
1565 icount += nextcall->prolog_instructioncount;
1567 /* end current block, or glue blocks together */
1569 n_bptr->icount = icount;
1571 if (nextcall->blockbefore) {
1572 close_prolog_block(iln, n_bptr, nextcall);
1578 /* check if the result is a local variable */
1580 if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
1581 && o_iptr->dst.varindex < iln->jd->localcount)
1583 nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
1586 nextcall->n_resultlocal = -1;
1588 /* set memory pointers in the callee */
1590 nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
1591 nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
1595 DOLOG( printf("%sentering inline ", indent);
1596 show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1598 inline_rewrite_method(nextcall);
1600 DOLOG( printf("%sleaving inline ", indent);
1601 show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1603 /* update memory cursors */
1605 assert(nextcall->inlined_iinstr_cursor
1606 <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
1607 assert(nextcall->inlined_basicblocks_cursor
1608 == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
1609 iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
1610 iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
1612 /* start new block, or glue blocks together */
1614 if (nextcall->blockafter) {
1615 n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
1619 n_bptr = iln->inlined_basicblocks_cursor - 1;
1620 icount = n_bptr->icount;
1624 /* emit inlining epilog */
1626 emit_inlining_epilog(iln, nextcall, o_iptr);
1627 icount += nextcall->epilog_instructioncount;
1629 /* proceed to next call */
1631 nextcall = nextcall->next;
1634 n_iptr = (iln->inlined_iinstr_cursor++);
1635 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1637 switch (o_iptr->opc) {
1639 if (iln->depth == 0)
1648 if (iln->depth == 0)
1651 retidx = iln->varmap[o_iptr->s1.varindex];
1652 if (iln->n_resultlocal != -1) {
1653 /* store result in a local variable */
1655 DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
1656 /* This relies on the same sequence of types for */
1657 /* ?STORE and ?RETURN opcodes. */
1658 n_iptr->opc = ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN);
1659 n_iptr->s1.varindex = retidx;
1660 n_iptr->dst.varindex = iln->n_resultlocal;
1661 n_iptr->sx.s23.s3.javaindex = UNUSED; /* XXX set real javaindex? */
1666 n_iptr = (iln->inlined_iinstr_cursor++);
1667 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1670 else if ((retidx < resultjd->localcount && iln->blockafter)
1671 || !iln->blockafter) /* XXX do we really always need the MOVE? */
1673 /* local must not become outvar, insert a MOVE */
1675 n_iptr->opc = ICMD_MOVE;
1676 n_iptr->s1.varindex = retidx;
1677 retidx = inline_new_temp_variable(resultjd,
1678 resultjd->var[retidx].type);
1679 n_iptr->dst.varindex = retidx;
1681 n_iptr = (iln->inlined_iinstr_cursor++);
1682 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1686 if (iln->blockafter) {
1687 n_iptr->opc = ICMD_GOTO;
1688 n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
1689 inline_add_block_reference(iln, &(n_iptr->dst.block));
1692 n_iptr->opc = ICMD_NOP;
1696 if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
1697 n_iptr->opc = ICMD_NOP;
1706 inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
1709 DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
1718 /* end of basic block */
1720 if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
1721 close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
1722 n_bptr->icount = icount;
1724 DOLOG( printf("closed body block:\n");
1725 show_basicblock(resultjd, n_bptr, SHOW_STACK); );
1728 n_bptr->icount = icount;
1729 assert(iln->parent);
1730 if (retidx != UNUSED)
1731 iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
1735 bm = iln->ctx->blockmap;
1736 for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
1737 assert(bm->iln && bm->o_block && bm->n_block);
1739 inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block, false);
1742 #if !defined(NDEBUG)
1744 inline_target_ref *ref;
1747 if (!iln->depth || ref->isnumber || *(ref->ref.block) != INLINE_RETURN_REFERENCE(iln)) {
1748 DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
1749 (void*)*(ref->ref.block)) );
1759 static exception_entry * inline_exception_tables(inline_node *iln,
1760 exception_entry *n_extable,
1761 exception_entry **prevextable)
1765 exception_entry *et;
1769 assert(prevextable);
1771 child = iln->children;
1774 n_extable = inline_exception_tables(child, n_extable, prevextable);
1775 child = child->next;
1776 } while (child != iln->children);
1779 et = iln->jd->exceptiontable;
1780 for (; et != NULL; et = et->down) {
1782 MZERO(n_extable, exception_entry, 1);
1783 n_extable->start = inline_map_block(iln, et->start , iln);
1784 n_extable->end = inline_map_block(iln, et->end , iln);
1785 n_extable->handler = inline_map_block(iln, et->handler, iln);
1786 n_extable->catchtype = et->catchtype;
1789 (*prevextable)->down = n_extable;
1791 *prevextable = n_extable;
1796 if (iln->handler_monitorexit) {
1797 exception_entry **activehandlers;
1799 MZERO(n_extable, exception_entry, 1);
1800 n_extable->start = iln->inlined_basicblocks;
1801 n_extable->end = iln->inlined_basicblocks_cursor;
1802 n_extable->handler = iln->handler_monitorexit;
1803 n_extable->catchtype.any = NULL; /* finally */
1806 (*prevextable)->down = n_extable;
1808 *prevextable = n_extable;
1812 /* We have to protect the created handler with the same handlers */
1813 /* that protect the method body itself. */
1815 for (scope = iln; scope->parent != NULL; scope = scope->parent) {
1817 activehandlers = scope->o_handlers;
1818 assert(activehandlers);
1820 while (*activehandlers) {
1822 assert(scope->parent);
1824 MZERO(n_extable, exception_entry, 1);
1825 n_extable->start = iln->handler_monitorexit;
1826 n_extable->end = iln->handler_monitorexit + 1; /* XXX ok in this case? */
1827 n_extable->handler = inline_map_block(scope->parent,
1828 (*activehandlers)->handler,
1830 n_extable->catchtype = (*activehandlers)->catchtype;
1833 (*prevextable)->down = n_extable;
1835 *prevextable = n_extable;
1847 static void inline_locals(inline_node *iln)
1853 iln->varmap = create_variable_map(iln);
1855 child = iln->children;
1858 inline_locals(child);
1859 child = child->next;
1860 } while (child != iln->children);
1863 if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
1864 iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
1865 if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
1866 iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
1867 if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
1868 iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
1872 static void inline_interface_variables(inline_node *iln)
1879 resultjd = iln->ctx->resultjd;
1881 resultjd->interface_map = DMNEW(interface_info, 5*iln->ctx->maxinoutdepth);
1882 for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
1883 resultjd->interface_map[i].flags = UNUSED;
1885 for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
1886 assert(bptr->indepth <= iln->ctx->maxinoutdepth);
1887 assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
1889 for (i=0; i<bptr->indepth; ++i) {
1890 v = &(resultjd->var[bptr->invars[i]]);
1892 if (v->type == TYPE_RET)
1893 v->flags |= PREALLOC;
1895 v->flags &= ~PREALLOC;
1896 v->flags &= ~INMEMORY;
1897 assert(bptr->invars[i] >= resultjd->localcount);
1899 if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1900 resultjd->interface_map[5*i + v->type].flags = v->flags;
1903 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1907 for (i=0; i<bptr->outdepth; ++i) {
1908 v = &(resultjd->var[bptr->outvars[i]]);
1910 if (v->type == TYPE_RET)
1911 v->flags |= PREALLOC;
1913 v->flags &= ~PREALLOC;
1914 v->flags &= ~INMEMORY;
1915 assert(bptr->outvars[i] >= resultjd->localcount);
1917 if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1918 resultjd->interface_map[5*i + v->type].flags = v->flags;
1921 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1928 static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
1933 builtintable_entry *bte;
1938 child = iln->children;
1941 inline_write_exception_handlers(master, child);
1942 child = child->next;
1943 } while (child != iln->children);
1946 if (iln->synchronize) {
1947 /* create the monitorexit handler */
1948 n_bptr = create_block(master, iln, iln,
1949 iln->n_passthroughcount + 1);
1950 n_bptr->type = BBTYPE_EXH;
1951 n_bptr->flags = BBFINISHED;
1953 exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1954 n_bptr->invars[iln->n_passthroughcount] = exvar;
1956 iln->handler_monitorexit = n_bptr;
1958 /* ACONST / ALOAD */
1960 n_ins = master->inlined_iinstr_cursor++;
1961 if (iln->m->flags & ACC_STATIC) {
1962 n_ins->opc = ICMD_ACONST;
1963 n_ins->sx.val.c.cls = iln->m->class;
1964 n_ins->flags.bits = INS_FLAG_CLASS;
1967 n_ins->opc = ICMD_ALOAD;
1968 n_ins->s1.varindex = iln->synclocal;
1969 assert(n_ins->s1.varindex != UNUSED);
1971 /* XXX could be PREALLOCed for builtin call */
1972 syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1973 n_ins->dst.varindex = syncvar;
1978 bte = builtintable_get_internal(LOCK_monitor_exit);
1980 n_ins = master->inlined_iinstr_cursor++;
1981 n_ins->opc = ICMD_BUILTIN;
1982 n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
1983 n_ins->sx.s23.s2.args = DMNEW(s4, n_ins->s1.argcount);
1984 n_ins->sx.s23.s2.args[0] = syncvar;
1985 for (i=0; i < iln->n_passthroughcount + 1; ++i) {
1986 n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
1988 n_ins->sx.s23.s3.bte = bte;
1993 n_ins = master->inlined_iinstr_cursor++;
1994 n_ins->opc = ICMD_ATHROW;
1995 n_ins->flags.bits = 0;
1996 n_ins->s1.varindex = exvar;
1999 /* close basic block */
2001 close_block(iln, iln, n_bptr, iln->n_passthroughcount);
2007 /* second pass driver *********************************************************/
2009 static bool inline_transform(inline_node *iln, jitdata *jd)
2014 exception_entry *n_ext;
2015 exception_entry *prevext;
2019 #if defined(INLINE_VERIFY_RESULT)
2020 static int debug_verify_inlined_code = 1;
2022 #if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
2023 static int debug_counter = 0;
2026 DOLOG( dump_inline_tree(iln, 0); );
2030 n_ins = DMNEW(instruction, iln->cumul_instructioncount);
2031 MZERO(n_ins, instruction, iln->cumul_instructioncount);
2032 iln->inlined_iinstr = n_ins;
2034 n_bb = DMNEW(basicblock, iln->cumul_basicblockcount);
2035 MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
2036 iln->inlined_basicblocks = n_bb;
2038 iln->ctx->blockmap = DMNEW(inline_block_map, iln->cumul_blockmapcount);
2040 n_jd = jit_jitdata_new(iln->m);
2041 n_jd->flags = jd->flags;
2042 n_jd->code->optlevel = jd->code->optlevel;
2043 iln->ctx->resultjd = n_jd;
2047 /* create the local_map */
2049 n_jd->local_map = DMNEW(s4, 5*iln->cumul_maxlocals);
2050 for (i=0; i<5*iln->cumul_maxlocals; ++i)
2051 n_jd->local_map[i] = UNUSED;
2053 /* create / coalesce local variables */
2061 n_jd->localcount = n_jd->vartop;
2063 /* extra variables for verification (debugging) */
2065 #if defined(INLINE_VERIFY_RESULT)
2066 if (debug_verify_inlined_code) {
2067 n_jd->vartop += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
2068 if (n_jd->vartop > n_jd->varcount) {
2070 n_jd->var = DMREALLOC(n_jd->var, varinfo, n_jd->varcount, n_jd->vartop);
2071 n_jd->varcount = n_jd->vartop;
2074 #endif /* defined(INLINE_VERIFY_RESULT) */
2076 /* write inlined code */
2078 inline_rewrite_method(iln);
2080 /* create exception handlers */
2082 inline_write_exception_handlers(iln, iln);
2084 /* write the dummy end block */
2086 n_bptr = create_block(iln, iln, iln, 0);
2087 n_bptr->flags = BBUNDEF;
2088 n_bptr->type = BBTYPE_STD;
2090 /* store created code in jitdata */
2092 n_jd->basicblocks = iln->inlined_basicblocks;
2093 n_jd->instructioncount = iln->cumul_instructioncount;
2094 n_jd->instructions = iln->inlined_iinstr;
2096 /* link the basic blocks (dummy end block is not counted) */
2098 n_jd->basicblockcount = (iln->inlined_basicblocks_cursor - iln->inlined_basicblocks) - 1;
2099 for (i=0; i<n_jd->basicblockcount + 1; ++i)
2100 n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
2102 n_jd->basicblocks[i-1].next = NULL;
2104 /* check basicblock numbers */
2106 #if !defined(NDEBUG)
2107 jit_check_basicblock_numbers(n_jd);
2110 /* create the exception table */
2112 if (iln->cumul_exceptiontablelength) {
2113 exception_entry *tableend;
2115 n_ext = DMNEW(exception_entry, iln->cumul_exceptiontablelength);
2117 tableend = inline_exception_tables(iln, n_ext, &prevext);
2118 assert(tableend == n_ext + iln->cumul_exceptiontablelength);
2120 prevext->down = NULL;
2122 n_jd->exceptiontablelength = iln->cumul_exceptiontablelength;
2123 n_jd->exceptiontable = n_ext;
2129 /*******************************************************************************/
2132 memcpy(n_cd, jd->cd, sizeof(codegendata));
2134 n_cd->method = NULL; /* XXX */
2135 n_jd->maxlocals = iln->cumul_maxlocals;
2136 n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
2138 inline_post_process(n_jd);
2140 inline_interface_variables(iln);
2142 /* for debugging, verify the inlined result */
2144 #if defined(INLINE_VERIFY_RESULT)
2145 if (debug_verify_inlined_code) {
2146 debug_verify_inlined_code = 0;
2147 DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
2148 if (!typecheck(n_jd)) {
2149 *exceptionptr = NULL;
2150 DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
2154 DOLOG( printf("VERIFICATION PASSED.\n") );
2156 debug_verify_inlined_code = 1;
2158 #endif /* defined(INLINE_VERIFY_RESULT) */
2160 /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
2162 n_jd->rd->freemem = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
2163 #if defined(HAS_4BYTE_STACKSLOT)
2164 n_jd->rd->freemem_2 = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
2167 #if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
2168 if ( (n_jd->instructioncount >= opt_inline_debug_min_size)
2169 && (n_jd->instructioncount <= opt_inline_debug_max_size))
2171 if (debug_counter <= opt_inline_debug_end_counter)
2172 #endif /* defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG) */
2174 /* install the inlined result */
2176 *jd->code = *n_jd->code;
2177 n_jd->code = jd->code;
2180 /* statistics and logging */
2182 #if !defined(NDEBUG)
2183 inline_stat_roots++;
2186 printf("==== %d.INLINE ==================================================================\n",
2188 printf("\ninline tree:\n");
2189 dump_inline_tree(iln, 0);
2190 n_jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE | JITDATA_FLAG_SHOWDISASSEMBLE;
2191 /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
2192 printf("-------- DONE -----------------------------------------------------------\n");
2198 #if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
2206 /******************************************************************************/
2207 /* FIRST PASS: build inlining tree */
2208 /******************************************************************************/
2211 /* inline_pre_parse_heuristics *************************************************
2213 Perform heuristic checks whether a call site should be inlined.
2214 These checks are evaluated before the callee has been parsed and analysed.
2217 caller...........inlining node of the caller
2218 callee...........the called method
2219 site.............information on the call site
2222 true........consider for inlining
2223 false.......don't inline
2225 *******************************************************************************/
2227 static bool inline_pre_parse_heuristics(const inline_node *caller,
2228 const methodinfo *callee,
2231 #if defined(INLINE_MAX_DEPTH)
2232 if (caller->depth >= INLINE_MAX_DEPTH)
2240 /* inline_post_parse_heuristics ************************************************
2242 Perform heuristic checks whether a call site should be inlined.
2243 These checks are evaluated after the callee has been parsed and analysed.
2246 caller...........inlining node of the caller (const)
2247 callee...........the called method (const)
2250 true........consider for inlining
2251 false.......don't inline
2253 *******************************************************************************/
2255 static bool inline_post_parse_heuristics(const inline_node *caller,
2256 const inline_node *callee)
2262 /* inline_afterwards_heuristics ************************************************
2264 Perform heuristic checks whether a call site should be inlined.
2265 These checks are evaluated after the inlining plan for the callee has
2269 caller...........inlining node of the caller (const)
2270 callee...........the called method (const)
2273 true........consider for inlining
2274 false.......don't inline
2276 *******************************************************************************/
2278 static bool inline_afterwards_heuristics(const inline_node *caller,
2279 const inline_node *callee)
2281 inline_node *cumulator;
2283 #if defined(INLINE_DEPTH_FIRST)
2286 cumulator = caller->ctx->master;
2290 #if defined(INLINE_MAX_BLOCK_EXPANSION)
2291 || (cumulator->cumul_basicblockcount + callee->cumul_basicblockcount
2292 > INLINE_MAX_BLOCK_EXPANSION*caller->ctx->master->jd->basicblockcount)
2294 #if defined(INLINE_MAX_ICMD_EXPANSION)
2295 || (cumulator->cumul_instructioncount + callee->cumul_instructioncount
2296 > INLINE_MAX_ICMD_EXPANSION*caller->ctx->master->jd->instructioncount)
2307 /* inline_is_monomorphic *******************************************************
2309 Check if the given call site can be proven to be monomorphic.
2312 callee...........the called method
2313 call.............the invocation instruction
2316 site->speculative.....flags whether the inlining is speculative
2317 (only defined if return value is true)
2320 true if the call site is (currently) monomorphic,
2321 false if not or unknown
2323 *******************************************************************************/
2325 static bool inline_is_monomorphic(const methodinfo *callee,
2326 const instruction *call,
2329 if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
2330 || call->opc == ICMD_INVOKESPECIAL))
2332 site->speculative = false;
2336 /* XXX search single implementation for abstract monomorphics */
2338 if ((callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED
2340 == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED))
2343 DOLOG( printf("SPECULATIVE INLINE: "); method_println((methodinfo*)callee); );
2344 site->speculative = true;
2350 /* possibly polymorphic call site */
2356 /* inline_can_inline ***********************************************************
2358 Check if inlining of the given call site is possible.
2361 caller...........inlining node of the caller
2362 callee...........the called method
2363 call.............the invocation instruction
2366 site->speculative.....flags whether the inlining is speculative
2367 (only defined if return value is true)
2370 true if inlining is possible, false if not
2372 *******************************************************************************/
2374 static bool inline_can_inline(const inline_node *caller,
2375 const methodinfo *callee,
2376 const instruction *call,
2379 const inline_node *active;
2381 /* cannot inline native methods */
2383 if (callee->flags & ACC_NATIVE)
2386 /* cannot inline possibly polymorphic calls */
2388 if (!inline_is_monomorphic(callee, call, site))
2391 /* cannot inline recursive calls */
2393 for (active = caller; active; active = active->parent) {
2394 if (callee == active->m) {
2395 DOLOG( printf("RECURSIVE!\n") );
2400 /* inlining is possible */
2406 /* inline_create_callee_node ***************************************************
2408 Create an inlining node for the given callee.
2411 caller...........inlining node of the caller (const)
2412 callee...........the called method
2415 the new inlining node
2417 *******************************************************************************/
2419 static inline_node * inline_create_callee_node(const inline_node *caller,
2422 inline_node *cn; /* the callee inline_node */
2424 cn = DNEW(inline_node);
2425 MZERO(cn, inline_node, 1);
2427 cn->depth = caller->depth + 1;
2428 cn->ctx = caller->ctx;
2430 cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
2431 cn->isstatic = (callee->flags & ACC_STATIC);
2437 /* inline_set_callee_properties ************************************************
2439 Set properties of the inlined call site.
2442 caller...........inlining node of the caller (const)
2443 cn...............the called method
2444 site.............info about the call site (const)
2447 *cn..............has the properties set
2449 *******************************************************************************/
2451 static void inline_set_callee_properties(const inline_node *caller,
2453 const inline_site *site)
2459 /* set info about the call site */
2461 cn->callerblock = site->bptr;
2462 cn->callerins = site->iptr;
2463 cn->callerpc = site->pc;
2464 cn->o_handlers = site->handlers;
2465 cn->n_handlercount = caller->n_handlercount + site->nhandlers;
2467 /* determine if we need basic block boundaries before/after */
2469 cn->blockbefore = false;
2470 cn->blockafter = false;
2472 if (cn->jd->branchtoentry)
2473 cn->blockbefore = true;
2475 if (cn->jd->branchtoend)
2476 cn->blockafter = true;
2478 if (cn->jd->returncount > 1)
2479 cn->blockafter = true;
2481 /* XXX make safer and reusable (maybe store last real block) */
2482 for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
2485 if (cn->jd->returnblock != bptr)
2486 cn->blockafter = true;
2488 /* info about the callee */
2490 cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
2491 cn->prolog_instructioncount = cn->m->parseddesc->paramcount + 2;
2492 cn->epilog_instructioncount = 1; /* INLINE_END */
2493 cn->extra_instructioncount = 0;
2495 /* we need a CHECKNULL for instance methods, except for <init> */
2497 if (!cn->isstatic && cn->m->name != utf_init)
2498 cn->prolog_instructioncount += 1;
2500 /* deal with synchronized callees */
2502 if (cn->synchronize) {
2504 builtintable_entry *bte;
2506 /* we need basic block boundaries because of the handler */
2508 cn->blockbefore = true;
2509 cn->blockafter = true;
2511 /* for synchronized static methods */
2512 /* we need an ACONST, MONITORENTER in the prolog */
2513 /* and ACONST, MONITOREXIT in the epilog */
2515 /* for synchronized instance methods */
2516 /* we need an COPY, MONITORENTER in the prolog */
2517 /* and MONITOREXIT in the epilog */
2520 cn->prolog_instructioncount += 2;
2521 cn->epilog_instructioncount += 2;
2524 cn->prolog_instructioncount += 2;
2525 cn->epilog_instructioncount += 1;
2526 cn->localsoffset += 1;
2529 /* and exception handler */
2530 /* ALOAD, builtin_monitorexit, ATHROW */
2532 cn->extra_instructioncount += 3;
2534 /* exception table entries */
2536 cn->extra_exceptiontablelength = 1 + cn->n_handlercount;
2538 /* add exception handler block */
2540 cn->cumul_basicblockcount_root++;
2542 /* we must call the builtins */
2544 bte = builtintable_get_internal(LOCK_monitor_enter);
2546 if (md->memuse > cn->regdata->memuse)
2547 cn->regdata->memuse = md->memuse;
2548 if (md->argintreguse > cn->regdata->argintreguse)
2549 cn->regdata->argintreguse = md->argintreguse;
2551 bte = builtintable_get_internal(LOCK_monitor_exit);
2553 if (md->memuse > cn->regdata->memuse)
2554 cn->regdata->memuse = md->memuse;
2555 if (md->argintreguse > cn->regdata->argintreguse)
2556 cn->regdata->argintreguse = md->argintreguse;
2559 /* determine pass-through variables */
2561 i = site->iptr->s1.argcount - cn->m->parseddesc->paramcount; /* max # of pass-though vars */
2563 cn->n_passthroughvars = DMNEW(s4, i);
2565 for (argi = site->iptr->s1.argcount - 1; argi >= cn->m->parseddesc->paramcount; --argi) {
2566 s4 idx = site->iptr->sx.s23.s2.args[argi];
2567 if (idx >= caller->jd->localcount) {
2568 cn->n_passthroughvars[j] = idx;
2572 DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
2576 cn->n_selfpassthroughcount = j;
2577 cn->n_passthroughcount = caller->n_passthroughcount + cn->n_selfpassthroughcount;
2581 /* inline_cumulate_counters ****************************************************
2583 Cumulate counters after a node has been decided to become inlined.
2586 caller...........inlining node of the caller
2587 callee...........inlining node of the callee (const)
2590 *caller..........gets cumulated values added
2592 *******************************************************************************/
2594 static void inline_cumulate_counters(inline_node *caller,
2595 const inline_node *cn)
2597 caller->cumul_instructioncount += cn->prolog_instructioncount;
2598 caller->cumul_instructioncount += cn->epilog_instructioncount;
2599 caller->cumul_instructioncount += cn->extra_instructioncount;
2600 caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
2602 caller->cumul_basicblockcount += cn->cumul_basicblockcount;
2603 caller->cumul_basicblockcount_root += cn->cumul_basicblockcount_root;
2604 caller->cumul_blockmapcount += cn->cumul_blockmapcount;
2605 caller->cumul_exceptiontablelength += cn->cumul_exceptiontablelength;
2606 caller->cumul_exceptiontablelength += cn->extra_exceptiontablelength;
2608 if (cn->cumul_maxlocals > caller->cumul_maxlocals)
2609 caller->cumul_maxlocals = cn->cumul_maxlocals;
2611 /* XXX extra block after inlined call */
2612 if (cn->blockafter) {
2613 caller->cumul_basicblockcount += 1;
2614 caller->cumul_blockmapcount += 1;
2619 /* inline_analyse_callee *******************************************************
2621 Analyse an inlining candidate callee.
2624 caller...........inlining node of the caller
2625 callee...........the called method
2626 site.............info about the call site
2629 site->inlined....true if the callee has been selected for inlining
2632 the inline node of the callee, or
2633 NULL if an error has occurred (don't use the inlining plan in this case)
2635 *******************************************************************************/
2637 static inline_node * inline_analyse_callee(inline_node *caller,
2641 inline_node *cn; /* the callee inline_node */
2643 /* create an inline tree node */
2645 cn = inline_create_callee_node(caller, callee);
2647 /* get the intermediate representation of the callee */
2649 if (!inline_jit_compile(cn))
2652 /* evaluate heuristics after parsing the callee */
2654 if (!inline_post_parse_heuristics(caller, cn))
2657 /* the call site will be inlined */
2659 site->inlined = true;
2661 /* set info about the call site */
2663 inline_set_callee_properties(caller, cn, site);
2665 /* insert the node into the inline tree */
2667 inline_insert_inline_node(caller, cn);
2669 /* analyse recursively */
2671 if (!inline_analyse_code(cn))
2674 if (!inline_afterwards_heuristics(caller, cn)) {
2675 #if defined(INLINE_CANCEL_ON_THRESHOLD)
2678 inline_remove_inline_node(caller, cn);
2679 caller->ctx->stopped = true;
2680 site->inlined = false;
2685 /* cumulate counters */
2687 #if defined(INLINE_DEPTH_FIRST)
2688 inline_cumulate_counters(caller, cn);
2691 #if defined(INLINE_BREADTH_FIRST)
2693 inline_cumulate_counters(caller, cn);
2694 caller = caller->parent;
2702 /* inline_process_candidate ****************************************************
2704 Process a selected inlining candidate.
2707 cand.............the candidate
2710 true........everything ok
2711 false.......an error has occurred, don't use the plan
2713 *******************************************************************************/
2715 static bool inline_process_candidate(inline_candidate *cand)
2719 cn = inline_analyse_callee(cand->caller,
2726 if (!cand->site.inlined)
2729 /* store assumptions */
2731 if (cand->site.speculative)
2732 method_add_assumption_monomorphic(cand->callee, cand->caller->ctx->master->m);
2738 /* inline_analyse_code *********************************************************
2740 Analyse the intermediate code of the given inlining node.
2743 iln..............the inlining node
2746 *iln.............the inlining plan
2749 true........everything ok
2750 false.......an error has occurred, don't use the plan
2752 *******************************************************************************/
2754 static bool inline_analyse_code(inline_node *iln)
2761 exception_entry **handlers;
2762 exception_entry *ex;
2773 /* initialize cumulative counters */
2775 iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
2776 iln->cumul_exceptiontablelength += mjd->exceptiontablelength;
2778 /* iterate over basic blocks */
2782 for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
2784 /* count the block */
2785 /* ignore dummy end blocks (but count them for the blockmap) */
2787 iln->cumul_blockmapcount++;
2788 if ((bptr != mjd->basicblocks || iln->blockbefore)
2790 (bptr->icount > 0 || bptr->next != NULL))
2791 iln->cumul_basicblockcount++;
2793 /* skip dead code */
2795 if (bptr->flags < BBREACHED)
2798 /* allocate the buffer of active exception handlers */
2799 /* XXX this wastes some memory, but probably it does not matter */
2801 handlers = DMNEW(exception_entry*, mjd->exceptiontablelength + 1);
2803 /* determine the active exception handlers for this block */
2804 /* XXX maybe the handlers of a block should be part of our IR */
2805 /* XXX this should share code with the type checkers */
2807 for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
2808 if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
2809 handlers[nhandlers++] = ex;
2812 handlers[nhandlers] = NULL;
2815 iptr = bptr->iinstr;
2818 iln->cumul_instructioncount += len;
2820 /* iterate over the instructions of the block */
2822 for (; --len >= 0; ++iptr) {
2824 switch (iptr->opc) {
2825 case ICMD_INVOKEVIRTUAL:
2826 case ICMD_INVOKESPECIAL:
2827 case ICMD_INVOKESTATIC:
2828 case ICMD_INVOKEINTERFACE:
2830 if (!INSTRUCTION_IS_UNRESOLVED(iptr) && !iln->ctx->stopped) {
2831 callee = iptr->sx.s23.s3.fmiref->p.method;
2833 if (inline_can_inline(iln, callee, iptr, &site)) {
2834 site.inlined = false;
2837 site.pc = blockendpc - len - 1;
2838 site.handlers = handlers;
2839 site.nhandlers = nhandlers;
2841 if (inline_pre_parse_heuristics(iln, callee, &site)) {
2842 #if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
2843 inline_add_candidate(iln->ctx, iln, callee, &site);
2845 inline_candidate cand;
2847 cand.callee = callee;
2850 if (!inline_process_candidate(&cand))
2864 /* extra ICMD_MOVE may be necessary */
2865 iln->cumul_instructioncount++;
2870 /* end of basic block */
2877 static void inline_cumulate_counters_recursive(inline_node *iln)
2881 child = iln->children;
2884 inline_cumulate_counters_recursive(child);
2885 inline_cumulate_counters(iln, child);
2886 child = child->next;
2887 } while (child != iln->children);
2892 /* inline_make_inlining_plan ***************************************************
2894 Make an inlining plan for the given root node
2897 iln..............the root node
2900 *iln.............the inlining plan
2903 true........everything ok
2904 false.......an error has occurred, don't use the plan
2906 *******************************************************************************/
2908 #if defined(INLINE_KNAPSACK)
2909 static bool inline_make_inlining_plan(inline_node *iln)
2911 inline_candidate *cand;
2912 #if defined(INLINE_COST_BUDGET)
2913 s4 budget = INLINE_COST_BUDGET;
2914 # define BUDGETMEMBER cost
2916 #if defined(INLINE_WEIGHT_BUDGET)
2917 double budget = INLINE_WEIGHT_BUDGET;
2918 # define BUDGETMEMBER weight
2921 inline_analyse_code(iln);
2923 DOLOG( printf("candidates in "); method_println(iln->m);
2924 inline_candidates_println(iln->ctx); );
2926 while ((cand = inline_pick_best_candidate(iln->ctx)) != NULL)
2928 if (cand->BUDGETMEMBER <= budget) {
2929 DOLOG( printf(" picking: "); inline_candidate_println(cand); );
2931 if (!inline_process_candidate(cand))
2934 #if !defined(INLINE_ADD_NEGATIVE_TO_BUDGET)
2935 if (cand->BUDGETMEMBER > 0)
2937 budget -= cand->BUDGETMEMBER;
2941 inline_cumulate_counters_recursive(iln);
2945 #endif /* defined(INLINE_KNAPSACK) */
2948 #if defined(INLINE_DEPTH_FIRST)
2949 static bool inline_make_inlining_plan(inline_node *iln)
2951 return inline_analyse_code(iln);
2953 #endif /* defined(INLINE_DEPTH_FIRST) */
2956 #if defined(INLINE_BREADTH_FIRST)
2957 static bool inline_make_inlining_plan(inline_node *iln)
2959 inline_candidate *cand;
2961 inline_analyse_code(iln);
2963 DOLOG( printf("candidates in "); method_println(iln->m);
2964 inline_candidates_println(iln->ctx); );
2966 while (!iln->ctx->stopped
2967 && (cand = inline_pick_best_candidate(iln->ctx)) != NULL)
2969 DOLOG( printf(" picking: "); inline_candidate_println(cand); );
2971 if (!inline_process_candidate(cand))
2977 #endif /* defined(INLINE_BREADTH_FIRST) */
2980 /* statistics *****************************************************************/
2982 #if defined(INLINE_STATISTICS)
2983 static void inline_gather_statistics_recursive(inline_node *iln)
2987 inline_stat_inlined_nodes++;
2989 if (iln->depth > inline_stat_max_depth)
2990 inline_stat_max_depth++;
2992 child = iln->children;
2995 inline_gather_statistics_recursive(child);
2996 child = child->next;
2997 } while (child != iln->children);
3000 #endif /* defined(INLINE_STATISTICS) */
3003 #if defined(INLINE_STATISTICS)
3004 static void inline_gather_statistics(inline_node *iln)
3006 inline_stat_roots_transformed++;
3008 inline_gather_statistics_recursive(iln);
3010 #endif /* defined(INLINE_STATISTICS) */
3013 /* post processing ************************************************************/
3015 #define POSTPROCESS_SRC(varindex) live[varindex]--
3016 #define POSTPROCESS_DST(varindex) live[varindex]++
3018 #define POSTPROCESS_SRCOP(s) POSTPROCESS_SRC(iptr->s.varindex)
3019 #define POSTPROCESS_DSTOP(d) POSTPROCESS_DST(iptr->d.varindex)
3021 #define MARKSAVED(varindex) jd->var[varindex].flags |= SAVEDVAR
3023 #define MARK_ALL_SAVED \
3025 for (i=0; i<jd->vartop; ++i) \
3030 static void inline_post_process(jitdata *jd)
3036 icmdtable_entry_t *icmdt;
3039 builtintable_entry *bte;
3041 /* reset the SAVEDVAR flag of all variables */
3043 for (i=0; i<jd->vartop; ++i)
3044 jd->var[i].flags &= ~SAVEDVAR;
3046 /* allocate the life counters */
3048 live = DMNEW(s4, jd->vartop);
3049 MZERO(live, s4, jd->vartop);
3051 /* iterate over all basic blocks */
3053 for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
3054 if (bptr->flags < BBREACHED)
3057 /* make invars live */
3059 for (i=0; i<bptr->indepth; ++i)
3060 POSTPROCESS_DST(bptr->invars[i]);
3062 iptr = bptr->iinstr;
3063 iend = iptr + bptr->icount;
3065 for (; iptr < iend; ++iptr) {
3067 icmdt = &(icmd_table[iptr->opc]);
3069 switch (icmdt->dataflow) {
3071 POSTPROCESS_SRCOP(sx.s23.s3);
3073 POSTPROCESS_SRCOP(sx.s23.s2);
3075 POSTPROCESS_SRCOP(s1);
3077 if (icmdt->flags & ICMDTABLE_CALLS) {
3078 jd->isleafmethod = false;
3084 POSTPROCESS_SRCOP(sx.s23.s2);
3087 POSTPROCESS_SRCOP(s1);
3089 if (icmdt->flags & ICMDTABLE_CALLS) {
3090 jd->isleafmethod = false;
3094 POSTPROCESS_DSTOP(dst);
3098 for (i=0; i<iptr->s1.argcount; ++i) {
3099 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
3101 if (icmdt->flags & ICMDTABLE_CALLS) {
3102 jd->isleafmethod = false;
3105 POSTPROCESS_DSTOP(dst);
3109 INSTRUCTION_GET_METHODDESC(iptr, md);
3111 jd->isleafmethod = false;
3112 for (i=0; i<md->paramcount; ++i) {
3113 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
3115 for (; i<iptr->s1.argcount; ++i) {
3116 MARKSAVED(iptr->sx.s23.s2.args[i]);
3118 if (md->returntype.type != TYPE_VOID)
3119 POSTPROCESS_DSTOP(dst);
3123 bte = iptr->sx.s23.s3.bte;
3125 goto post_process_call;
3131 } /* end instruction loop */
3133 /* consume outvars */
3135 for (i=0; i<bptr->outdepth; ++i)
3136 POSTPROCESS_SRC(bptr->outvars[i]);
3138 #if !defined(NDEBUG)
3139 for (i=jd->localcount; i < jd->vartop; ++i)
3140 assert(live[i] == 0);
3143 } /* end basic block loop */
3147 /* inline_create_root_node *****************************************************
3149 Create the root node of the inlining tree.
3152 jd...............the current jitdata of the root method
3155 the root node of the inlining tree
3157 *******************************************************************************/
3159 static inline_node * inline_create_root_node(jitdata *jd)
3163 iln = DNEW(inline_node);
3164 MZERO(iln, inline_node, 1);
3168 iln->regdata = jd->rd;
3170 iln->blockbefore = true;
3171 iln->blockafter = true;
3173 iln->cumul_instructioncount = 0;
3174 iln->cumul_basicblockcount = 1 /* dummy end block */;
3176 /* create inlining context */
3178 iln->ctx = DNEW(inline_context);
3179 MZERO(iln->ctx, inline_context, 1);
3180 iln->ctx->master = iln;
3181 iln->ctx->next_debugnr = 1; /* XXX debug */
3187 /******************************************************************************/
3188 /* MAIN DRIVER FUNCTION */
3189 /******************************************************************************/
3191 bool inline_inline(jitdata *jd)
3195 DOLOG( printf("==== INLINE ==================================================================\n");
3196 show_method(jd, SHOW_STACK); );
3198 #if defined(INLINE_STATISTICS)
3199 inline_stat_roots++;
3202 iln = inline_create_root_node(jd);
3204 if (inline_make_inlining_plan(iln)) {
3206 /* add blocks to the root node */
3208 iln->cumul_basicblockcount += iln->cumul_basicblockcount_root;
3209 iln->cumul_blockmapcount += iln->cumul_basicblockcount_root;
3211 DOLOG( printf("==== INLINE TRANSFORM ========================================================\n"); );
3214 inline_transform(iln, jd);
3216 #if defined(INLINE_STATISTICS)
3217 inline_gather_statistics(iln);
3221 DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
3228 * These are local overrides for various environment variables in Emacs.
3229 * Please do not remove this and leave it at the end of the file, where
3230 * Emacs will automagically detect them.
3231 * ---------------------------------------------------------------------
3234 * indent-tabs-mode: t
3238 * vim:noexpandtab:sw=4:ts=4: