1 /* src/vm/jit/inline/inline.c - method inlining
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Edwin Steiner
31 $Id: inline.c 6003 2006-11-15 23:24:46Z edwin $
44 #include "mm/memory.h"
45 #include "toolbox/logging.h"
46 #include "vm/builtin.h"
47 #include "vm/global.h"
48 #include "vm/options.h"
49 #include "vm/statistics.h"
50 #include "vm/jit/jit.h"
51 #include "vm/jit/parse.h"
52 #include "vm/jit/inline/inline.h"
53 #include "vm/jit/loop/loop.h"
56 #include "vm/initialize.h"
57 #include "vm/method.h"
58 #include "vm/jit/jit.h"
59 #include "vm/jit/show.h"
61 #include "vm/jit/reg.h"
62 #include "vm/jit/stack.h"
64 #include "vm/jit/verify/typecheck.h"
66 #if defined(ENABLE_THREADS)
67 # include "threads/native/threads.h"
71 /* debugging ******************************************************************/
74 #define INLINE_VERBOSE
75 bool inline_debug_log = 0;
76 bool inline_debug_log_names = 0;
77 int inline_debug_start_counter = 0;
78 int inline_debug_max_size = INT_MAX;
79 int inline_debug_min_size = 0;
80 int inline_debug_end_counter = INT_MAX;
81 int inline_count_methods = 0;
82 #define DOLOG(code) do{ if (inline_debug_log) { code; } }while(0)
88 /* types **********************************************************************/
90 typedef struct inline_node inline_node;
91 typedef struct inline_target_ref inline_target_ref;
92 typedef struct inline_context inline_context;
93 typedef struct inline_block_map inline_block_map;
100 inline_node *children;
101 inline_node *next; /* next node at this depth */
102 inline_node *prev; /* prev node at this depth */
103 int depth; /* inlining depth, 0 for root */
105 /* info about the call site (if depth > 0)*/
106 inline_node *parent; /* node of the caller (NULL for root) */
107 basicblock *callerblock; /* original block containing the INVOKE* */
108 instruction *callerins; /* the original INVOKE* instruction */
110 s4 *n_passthroughvars;
111 int n_passthroughcount;
112 int n_selfpassthroughcount; /* # of pass-through vars of the call itself */
113 exception_entry **o_handlers;
114 int n_handlercount; /* # of handlers protecting this call */
116 int synclocal; /* variable used for synchr., or UNUSED */
118 bool blockbefore; /* block boundary before inlined body? */
119 bool blockafter; /* block boundary after inlined body? */
121 /* info about the callee */
123 int prolog_instructioncount; /* # of ICMDs in the inlining prolog */
124 int epilog_instructioncount; /* # of ICMDs in the inlining epilog */
125 int extra_instructioncount;
126 int instructioncount;
127 bool synchronize; /* do we have to synchronize enter/exit? */
128 basicblock *handler_monitorexit; /* handler for synchronized inlinees */
131 /* cumulative values */
132 int cumul_instructioncount; /* ICMDs in this node and its children */
133 int cumul_basicblockcount; /* BBs started by this node and its children */
134 int cumul_blockmapcount;
136 int cumul_exceptiontablelength;
139 instruction *inlined_iinstr;
140 instruction *inlined_iinstr_cursor;
141 basicblock *inlined_basicblocks;
142 basicblock *inlined_basicblocks_cursor;
145 registerdata *regdata;
148 inline_target_ref *refs;
149 instruction *inline_start_instruction;
157 struct inline_target_ref {
158 inline_target_ref *next;
163 struct inline_block_map {
169 struct inline_context {
174 int next_block_number;
175 inline_block_map *blockmap;
182 int next_debugnr; /* XXX debug */
186 /* prototypes *****************************************************************/
188 static bool inline_inline_intern(methodinfo *m, inline_node *iln);
189 static void inline_post_process(jitdata *jd);
192 /* debug helpers **************************************************************/
195 #include "inline_debug.inc"
197 void inline_print_stats()
199 printf("inlined callers: %d\n", inline_count_methods);
204 /* compilation of callees *****************************************************/
206 static bool inline_jit_compile_intern(jitdata *jd)
210 /* XXX should share code with jit.c */
214 /* XXX initialize the static function's class */
218 /* call the compiler passes ***********************************************/
220 /* call parse pass */
222 DOLOG( log_message_class("Parsing ", m->class) );
227 /* call stack analysis pass */
229 if (!stack_analyse(jd)) {
237 static bool inline_jit_compile(inline_node *iln)
243 /* XXX should share code with jit.c */
249 #if defined(ENABLE_THREADS)
250 /* enter a monitor on the method */
251 lock_monitor_enter((java_objectheader *) m);
254 /* allocate jitdata structure and fill it */
256 jd = jit_jitdata_new(m);
259 jd->flags = 0; /* XXX */
261 /* initialize the register allocator */
265 /* setup the codegendata memory */
267 /* XXX do a pseudo setup */
268 jd->cd = DNEW(codegendata);
269 MZERO(jd->cd, codegendata, 1);
270 jd->cd->maxstack = m->maxstack;
272 /* XXX uses too much dump memory codegen_setup(jd); */
274 /* now call internal compile function */
276 r = inline_jit_compile_intern(jd);
279 iln->regdata = jd->rd;
282 /* free some memory */
285 #if defined(ENABLE_JIT)
286 # if defined(ENABLE_INTRP)
294 #if defined(ENABLE_THREADS)
295 /* leave the monitor */
296 lock_monitor_exit((java_objectheader *) m );
303 /* inlining tree handling *****************************************************/
305 static void insert_inline_node(inline_node *parent, inline_node *child)
310 assert(parent && child);
312 child->parent = parent;
314 child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
316 first = parent->children;
318 /* insert as only node */
319 parent->children = child;
325 /* {there is at least one child already there} */
327 /* XXX is this search necessary, or could we always add at the end? */
330 while (succ->callerpc < child->callerpc) {
333 /* insert as last node */
334 child->prev = first->prev;
336 child->prev->next = child;
337 child->next->prev = child;
342 assert(succ->callerpc > child->callerpc);
344 /* insert before succ */
346 child->prev = succ->prev;
348 child->prev->next = child;
349 child->next->prev = child;
353 /* variable handling **********************************************************/
355 static s4 inline_new_variable(jitdata *jd, s4 type, s4 flags)
360 index = jd->vartop++;
361 if (index >= jd->varcount) {
362 newcount = jd->vartop * 2; /* XXX */
363 jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, newcount);
364 MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
365 jd->varcount = newcount;
368 jd->var[index].type = type;
369 jd->var[index].flags = flags;
375 static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
380 v = &(origjd->var[origidx]);
382 newidx = inline_new_variable(jd, v->type, v->flags);
384 jd->var[newidx].vv = v->vv;
390 static s4 inline_new_temp_variable(jitdata *jd, s4 type)
392 return inline_new_variable(jd, type, 0);
396 static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
403 idx = inline_new_variable_clone(jd, origjd, index);
411 static s4 *create_variable_map(inline_node *callee)
420 /* create the variable mapping */
422 varmap = DMNEW(s4, callee->jd->varcount);
423 for (i=0; i<callee->jd->varcount; ++i)
426 /* translate local variables */
428 for (i=0; i<callee->m->maxlocals; ++i) {
429 for (t=0; t<5; ++t) {
430 idx = callee->jd->local_map[5*i + t];
434 v = &(callee->jd->var[idx]);
435 assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
436 v->type = t; /* XXX restore if it is TYPE_VOID */
438 avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
440 if (avail == UNUSED) {
441 avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, idx);
442 callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
449 /* for synchronized instance methods we need an extra local */
451 if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
452 n_idx = callee->localsoffset - 1;
454 assert(callee->parent);
455 assert(n_idx == callee->parent->localsoffset + callee->parent->m->maxlocals);
457 avail = callee->ctx->resultjd->local_map[5*n_idx + TYPE_ADR];
459 if (avail == UNUSED) {
460 avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
461 callee->ctx->resultjd->local_map[5*n_idx + TYPE_ADR] = avail;
464 callee->synclocal = avail;
467 callee->synclocal = UNUSED;
474 /* basic block translation ****************************************************/
476 #define INLINE_RETURN_REFERENCE(callee) \
477 ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
480 static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
482 inline_target_ref *ref;
484 ref = DNEW(inline_target_ref);
486 ref->next = iln->refs;
491 static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
496 assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
498 ctx->blockmap[ctx->blockmap_index].iln = iln;
499 ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
500 ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
502 ctx->blockmap_index++;
506 static basicblock * inline_map_block(inline_node *iln,
508 inline_node *targetiln)
510 inline_block_map *bm;
511 inline_block_map *bmend;
519 bm = iln->ctx->blockmap;
520 bmend = bm + iln->ctx->blockmap_index;
523 assert(bm->iln && bm->o_block && bm->n_block);
524 if (bm->o_block == o_block && bm->iln == targetiln)
530 return NULL; /* not reached */
534 static void inline_resolve_block_refs(inline_target_ref **refs,
538 inline_target_ref *ref;
539 inline_target_ref *prev;
544 if (*(ref->ref) == o_bptr) {
546 #if defined(INLINE_VERBOSE)
547 if (inline_debug_log) {
548 if ((ptrint) o_bptr < (0x333+100)) { /* XXX */
549 printf("resolving RETURN block reference %p -> new L%03d (%p)\n",
550 (void*)o_bptr, n_bptr->nr, (void*)n_bptr);
553 printf("resolving block reference old L%03d (%p) -> new L%03d (%p)\n",
554 o_bptr->nr, (void*)o_bptr, n_bptr->nr, (void*)n_bptr);
559 *(ref->ref) = n_bptr;
561 prev->next = ref->next;
575 /* basic block creation *******************************************************/
577 static basicblock * create_block(inline_node *container,
581 inline_target_ref **refs,
594 assert(indepth >= 0);
596 n_bptr = container->inlined_basicblocks_cursor++;
598 assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
600 BASICBLOCK_INIT(n_bptr, iln->m);
602 n_bptr->iinstr = container->inlined_iinstr_cursor;
603 n_bptr->next = n_bptr + 1;
604 n_bptr->nr = container->ctx->next_block_number++;
605 n_bptr->indepth = indepth;
606 n_bptr->flags = BBFINISHED; /* XXX */
608 /* set the inlineinfo of the new block */
610 if (iln->inline_start_instruction)
611 n_bptr->inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
613 if (indepth > container->ctx->maxinoutdepth)
614 container->ctx->maxinoutdepth = indepth;
617 n_bptr->invars = DMNEW(s4, indepth);
620 for (i=0; i<indepth; ++i)
621 n_bptr->invars[i] = -1; /* XXX debug */
623 /* pass-through variables enter the block */
625 outer = inner->parent;
626 while (outer != NULL) {
627 depth = outer->n_passthroughcount;
629 assert(depth + inner->n_selfpassthroughcount <= indepth);
631 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
632 varidx = inner->n_passthroughvars[i];
634 inline_new_variable_clone(container->ctx->resultjd,
637 n_bptr->invars[depth + i] = newvaridx;
638 outer->varmap[varidx] = newvaridx;
641 outer = outer->parent;
645 n_bptr->invars = NULL;
648 /* XXX move this to callers with o_bptr != NULL? */
651 inline_resolve_block_refs(refs, o_bptr, n_bptr);
654 /* XXX for the verifier. should not be here */
659 dv = DMNEW(varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
660 MZERO(dv, varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
661 n_bptr->inlocals = dv;
668 static s4 *translate_javalocals(inline_node *iln, s4 *javalocals)
673 jl = DMNEW(s4, iln->jd->maxlocals);
675 for (i=0; i<iln->jd->maxlocals; ++i) {
678 j = inline_translate_variable(iln->ctx->resultjd, iln->jd, iln->varmap, j);
686 static basicblock * create_body_block(inline_node *iln,
687 basicblock *o_bptr, s4 *varmap)
692 n_bptr = create_block(iln, iln, iln, o_bptr, &(iln->refs),
693 o_bptr->indepth + iln->n_passthroughcount);
695 n_bptr->type = o_bptr->type;
696 n_bptr->flags = o_bptr->flags;
698 /* translate the invars of the original block */
700 for (i=0; i<o_bptr->indepth; ++i) {
701 n_bptr->invars[iln->n_passthroughcount + i] =
702 inline_translate_variable(iln->ctx->resultjd, iln->jd,
707 /* translate javalocals info (not for dead code) */
709 if (n_bptr->flags >= BBREACHED)
710 n_bptr->javalocals = translate_javalocals(iln, o_bptr->javalocals);
716 static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
722 /* number of return variables */
724 retcount = (callee->n_resultlocal == -1
725 && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
727 /* start the epilog block */
729 n_bptr = create_block(caller, caller, callee, INLINE_RETURN_REFERENCE(callee),
730 &(callee->refs), callee->n_passthroughcount + retcount);
732 /* return variable */
735 idx = inline_new_variable(caller->ctx->resultjd,
736 callee->m->parseddesc->returntype.type, 0 /* XXX */);
737 n_bptr->invars[callee->n_passthroughcount] = idx;
738 varmap[callee->callerins->dst.varindex] = idx;
743 n_bptr->javalocals = DMNEW(s4, caller->jd->maxlocals);
744 MCOPY(n_bptr->javalocals, caller->javalocals, s4, caller->jd->maxlocals);
746 /* set block flags & type */
748 n_bptr->flags = /* XXX original block flags */ BBFINISHED;
749 n_bptr->type = BBTYPE_STD;
755 static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
762 n_bptr->outdepth = outdepth;
763 n_bptr->outvars = DMNEW(s4, outdepth);
765 for (i=0; i<outdepth; ++i)
766 n_bptr->outvars[i] = 0; /* XXX debug */
768 if (outdepth > iln->ctx->maxinoutdepth)
769 iln->ctx->maxinoutdepth = outdepth;
771 /* pass-through variables leave the block */
773 outer = inner->parent;
774 while (outer != NULL) {
775 depth = outer->n_passthroughcount;
777 assert(depth + inner->n_selfpassthroughcount <= outdepth);
779 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
780 varidx = inner->n_passthroughvars[i];
781 n_bptr->outvars[depth + i] =
782 inline_translate_variable(iln->ctx->resultjd,
788 outer = outer->parent;
793 static void close_prolog_block(inline_node *iln,
795 inline_node *nextcall)
797 /* XXX add original outvars! */
798 close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
800 /* pass-through variables */
802 DOLOG( printf("closed prolog block:\n");
803 show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
807 static void close_body_block(inline_node *iln,
816 close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
818 /* translate the outvars of the original block */
821 for (i=0; i<o_bptr->outdepth; ++i) {
822 n_bptr->outvars[iln->n_passthroughcount + i] =
823 inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
827 /* set the return variable, if any */
831 n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
836 /* inlined code generation ****************************************************/
838 static instruction * inline_instruction(inline_node *iln,
844 n_iptr = (iln->inlined_iinstr_cursor++);
845 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
847 n_iptr->opc = opcode;
848 n_iptr->flags.bits = o_iptr->flags.bits & INS_FLAG_ID_MASK;
849 n_iptr->line = o_iptr->line;
854 static void inline_generate_sync_builtin(inline_node *iln,
863 if (callee->m->flags & ACC_STATIC) {
865 syncvar = inline_new_temp_variable(iln->ctx->resultjd, TYPE_ADR);
867 n_ins = inline_instruction(iln, ICMD_ACONST, o_iptr);
868 n_ins->sx.val.c.cls = callee->m->class;
869 n_ins->dst.varindex = syncvar;
870 n_ins->flags.bits |= INS_FLAG_CLASS;
873 syncvar = instancevar;
876 assert(syncvar != UNUSED);
878 /* MONITORENTER / MONITOREXIT */
880 n_ins = inline_instruction(iln, ICMD_BUILTIN, o_iptr);
881 n_ins->sx.s23.s3.bte = builtintable_get_internal(func);
882 n_ins->s1.argcount = 1; /* XXX add through-vars */
883 n_ins->sx.s23.s2.args = DMNEW(s4, 1);
884 n_ins->sx.s23.s2.args[0] = syncvar;
887 static s4 emit_inlining_prolog(inline_node *iln,
899 insinfo_inline *insinfo;
902 assert(iln && callee && o_iptr);
905 md = calleem->parseddesc;
906 isstatic = (calleem->flags & ACC_STATIC);
908 /* INLINE_START instruction */
910 n_ins = inline_instruction(iln, ICMD_INLINE_START, o_iptr);
912 insinfo = DNEW(insinfo_inline);
913 insinfo->method = callee->m;
914 insinfo->outer = iln->m;
915 insinfo->synclocal = callee->synclocal;
916 insinfo->synchronize = callee->synchronize;
917 insinfo->javalocals_start = NULL;
918 insinfo->javalocals_end = NULL;
920 /* info about stack vars live at the INLINE_START */
922 insinfo->throughcount = callee->n_passthroughcount;
923 insinfo->paramcount = md->paramcount;
924 insinfo->stackvarscount = o_iptr->s1.argcount;
925 insinfo->stackvars = DMNEW(s4, insinfo->stackvarscount);
926 for (i=0; i<insinfo->stackvarscount; ++i)
927 insinfo->stackvars[i] = iln->varmap[o_iptr->sx.s23.s2.args[i]];
929 /* info about the surrounding inlining */
931 if (iln->inline_start_instruction)
932 insinfo->parent = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
934 insinfo->parent = NULL;
936 /* finish the INLINE_START instruction */
938 n_ins->sx.s23.s3.inlineinfo = insinfo;
939 callee->inline_start_instruction = n_ins;
941 DOLOG( printf("%sprolog: ", iln->indent);
942 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
944 /* handle parameters for the inlined callee */
946 localindex = callee->localsoffset + md->paramslots;
948 for (i=md->paramcount-1; i>=0; --i) {
951 type = md->paramtypes[i].type;
953 localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
954 assert(callee->regdata);
956 /* translate the argument variable */
958 argvar = varmap[o_iptr->sx.s23.s2.args[i]];
959 assert(argvar != UNUSED);
961 /* remove preallocation from the argument variable */
963 iln->ctx->resultjd->var[argvar].flags &= ~(PREALLOC | INMEMORY);
965 /* check the instance slot against NULL */
967 if (!isstatic && i == 0) {
968 assert(type == TYPE_ADR);
969 n_ins = inline_instruction(iln, ICMD_CHECKNULL, o_iptr);
970 n_ins->s1.varindex = argvar;
971 n_ins->dst.varindex = n_ins->s1.varindex;
974 /* store argument into local variable of inlined callee */
976 if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != UNUSED)
978 /* this value is used in the callee */
980 if (i == 0 && callee->synclocal != UNUSED) {
981 /* we also need it for synchronization, so copy it */
982 assert(type == TYPE_ADR);
983 n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
986 n_ins = inline_instruction(iln, ICMD_ISTORE + type, o_iptr);
987 n_ins->sx.s23.s3.javaindex = UNUSED;
989 n_ins->s1.varindex = argvar;
990 n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
991 assert(n_ins->dst.varindex != UNUSED);
993 else if (i == 0 && callee->synclocal != UNUSED) {
994 /* the value is not used inside the callee, but we need it for */
995 /* synchronization */
996 /* XXX In this case it actually makes no sense to create a */
997 /* separate synchronization variable. */
999 n_ins = inline_instruction(iln, ICMD_NOP, o_iptr);
1002 /* this value is not used, pop it */
1004 n_ins = inline_instruction(iln, ICMD_POP, o_iptr);
1005 n_ins->s1.varindex = argvar;
1008 DOLOG( printf("%sprolog: ", iln->indent);
1009 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1012 /* COPY for synchronized instance methods */
1014 if (callee->synclocal != UNUSED) {
1015 n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
1016 n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
1017 n_ins->dst.varindex = callee->synclocal;
1019 assert(n_ins->s1.varindex != UNUSED);
1022 if (callee->synchronize) {
1023 inline_generate_sync_builtin(iln, callee, o_iptr,
1024 (isstatic) ? UNUSED : varmap[o_iptr->sx.s23.s2.args[0]],
1025 LOCK_monitor_enter);
1032 static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
1037 assert(iln && callee && o_iptr);
1038 assert(callee->inline_start_instruction);
1040 if (callee->synchronize) {
1041 inline_generate_sync_builtin(iln, callee, o_iptr,
1046 /* INLINE_END instruction */
1048 n_ins = inline_instruction(iln, ICMD_INLINE_END, o_iptr);
1049 n_ins->sx.s23.s3.inlineinfo = callee->inline_start_instruction->sx.s23.s3.inlineinfo;
1051 /* set the javalocals */
1053 jl = DMNEW(s4, iln->jd->maxlocals);
1054 MCOPY(jl, iln->javalocals, s4, iln->jd->maxlocals);
1055 n_ins->sx.s23.s3.inlineinfo->javalocals_end = jl;
1057 DOLOG( printf("%sepilog: ", iln->indent);
1058 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1062 #define TRANSLATE_VAROP(vo) \
1063 n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
1066 static void inline_clone_instruction(inline_node *iln,
1070 instruction *o_iptr,
1071 instruction *n_iptr)
1073 icmdtable_entry_t *icmdt;
1074 builtintable_entry *bte;
1077 branch_target_t *table;
1078 lookup_target_t *lookup;
1083 icmdt = &(icmd_table[o_iptr->opc]);
1085 switch (icmdt->dataflow) {
1090 TRANSLATE_VAROP(sx.s23.s3);
1092 TRANSLATE_VAROP(sx.s23.s2);
1094 TRANSLATE_VAROP(s1);
1098 TRANSLATE_VAROP(sx.s23.s2);
1102 TRANSLATE_VAROP(s1);
1104 TRANSLATE_VAROP(dst);
1108 n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1109 for (i=0; i<n_iptr->s1.argcount; ++i) {
1110 n_iptr->sx.s23.s2.args[i] =
1111 inline_translate_variable(jd, origjd, varmap,
1112 o_iptr->sx.s23.s2.args[i]);
1114 TRANSLATE_VAROP(dst);
1118 INSTRUCTION_GET_METHODDESC(n_iptr, md);
1120 n_iptr->s1.argcount += iln->n_passthroughcount;
1121 n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1122 for (i=0; i<o_iptr->s1.argcount; ++i) {
1123 n_iptr->sx.s23.s2.args[i] =
1124 inline_translate_variable(jd, origjd, varmap,
1125 o_iptr->sx.s23.s2.args[i]);
1127 for (scope = iln; scope != NULL; scope = scope->parent) {
1128 for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
1129 n_iptr->sx.s23.s2.args[i++] =
1130 scope->parent->varmap[scope->n_passthroughvars[j]];
1133 if (md->returntype.type != TYPE_VOID)
1134 TRANSLATE_VAROP(dst);
1138 bte = n_iptr->sx.s23.s3.bte;
1146 switch (icmdt->controlflow) {
1148 TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
1152 inline_add_block_reference(iln, &(n_iptr->dst.block));
1156 inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
1160 i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
1162 table = DMNEW(branch_target_t, i);
1163 MCOPY(table, o_iptr->dst.table, branch_target_t, i);
1164 n_iptr->dst.table = table;
1167 inline_add_block_reference(iln, &(table->block));
1173 inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
1175 i = n_iptr->sx.s23.s2.lookupcount;
1176 lookup = DMNEW(lookup_target_t, i);
1177 MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
1178 n_iptr->dst.lookup = lookup;
1181 inline_add_block_reference(iln, &(lookup->target.block));
1187 /* XXX move this to dataflow section? */
1189 switch (n_iptr->opc) {
1195 /* XXX share code with stack.c */
1196 j = n_iptr->dst.varindex;
1197 i = n_iptr->sx.s23.s3.javaindex;
1199 if (n_iptr->flags.bits & INS_FLAG_RETADDR)
1200 iln->javalocals[i] = UNUSED;
1202 iln->javalocals[i] = j;
1203 if (n_iptr->flags.bits & INS_FLAG_KILL_PREV)
1204 iln->javalocals[i-1] = UNUSED;
1205 if (n_iptr->flags.bits & INS_FLAG_KILL_NEXT)
1206 iln->javalocals[i+1] = UNUSED;
1213 static void rewrite_method(inline_node *iln)
1217 instruction *o_iptr;
1218 instruction *n_iptr;
1219 inline_node *nextcall;
1221 inline_block_map *bm;
1226 char indent[100]; /* XXX debug */
1232 resultjd = iln->ctx->resultjd;
1236 nextcall = iln->children;
1239 for (i=0; i<iln->depth; ++i)
1242 iln->indent = indent;
1244 DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
1245 printf("%s(passthrough: %d+%d)\n",
1246 indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
1247 iln->n_passthroughcount); );
1249 /* set memory cursors */
1251 iln->inlined_iinstr_cursor = iln->inlined_iinstr;
1252 iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
1254 /* allocate temporary buffers */
1256 iln->javalocals = DMNEW(s4, iln->jd->maxlocals);
1258 /* loop over basic blocks */
1260 o_bptr = iln->jd->basicblocks;
1261 for (; o_bptr; o_bptr = o_bptr->next) {
1263 if (o_bptr->flags < BBREACHED) {
1265 /* ignore the dummy end block */
1267 if (o_bptr->icount == 0 && o_bptr->next == NULL) {
1268 /* enter the following block as translation, for exception handler ranges */
1269 inline_block_translation(iln, o_bptr, iln->inlined_basicblocks_cursor);
1274 printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
1276 o_bptr->nr, o_bptr->flags, o_bptr->type,
1278 method_println(iln->m);
1281 n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1283 /* enter it in the blockmap */
1285 inline_block_translation(iln, o_bptr, n_bptr);
1287 close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
1291 len = o_bptr->icount;
1292 o_iptr = o_bptr->iinstr;
1295 printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
1297 o_bptr->nr, o_bptr->flags, o_bptr->type,
1299 method_println(iln->m);
1300 show_basicblock(iln->jd, o_bptr, SHOW_STACK);
1303 if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
1304 /* create an inlined clone of this block */
1306 n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1309 /* enter it in the blockmap */
1311 inline_block_translation(iln, o_bptr, n_bptr);
1313 /* initialize the javalocals */
1315 MCOPY(iln->javalocals, n_bptr->javalocals, s4, iln->jd->maxlocals);
1320 /* continue caller block */
1322 n_bptr = iln->inlined_basicblocks_cursor - 1;
1323 icount = n_bptr->icount;
1325 /* translate the javalocals */
1327 jl = translate_javalocals(iln, o_bptr->javalocals);
1328 iln->inline_start_instruction->sx.s23.s3.inlineinfo->javalocals_start = jl;
1330 MCOPY(iln->javalocals, jl, s4, iln->jd->maxlocals);
1333 /* iterate over the ICMDs of this block */
1338 while (--len >= 0) {
1340 DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false, SHOW_STACK);
1343 /* handle calls that will be inlined */
1345 if (nextcall && o_iptr == nextcall->callerins) {
1347 /* write the inlining prolog */
1349 (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
1350 icount += nextcall->prolog_instructioncount;
1352 /* end current block, or glue blocks together */
1354 n_bptr->icount = icount;
1356 if (nextcall->blockbefore) {
1357 close_prolog_block(iln, n_bptr, nextcall);
1363 /* check if the result is a local variable */
1365 if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
1366 && o_iptr->dst.varindex < iln->jd->localcount)
1368 nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
1371 nextcall->n_resultlocal = -1;
1373 /* set memory pointers in the callee */
1375 nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
1376 nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
1380 DOLOG( printf("%sentering inline ", indent);
1381 show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1383 rewrite_method(nextcall);
1385 DOLOG( printf("%sleaving inline ", indent);
1386 show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1388 /* update memory cursors */
1390 assert(nextcall->inlined_iinstr_cursor
1391 <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
1392 assert(nextcall->inlined_basicblocks_cursor
1393 == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
1394 iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
1395 iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
1397 /* start new block, or glue blocks together */
1399 if (nextcall->blockafter) {
1400 n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
1404 n_bptr = iln->inlined_basicblocks_cursor - 1;
1405 icount = n_bptr->icount;
1409 /* emit inlining epilog */
1411 emit_inlining_epilog(iln, nextcall, o_iptr);
1412 icount += nextcall->epilog_instructioncount;
1414 /* proceed to next call */
1416 nextcall = nextcall->next;
1419 n_iptr = (iln->inlined_iinstr_cursor++);
1420 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1422 switch (o_iptr->opc) {
1424 if (iln->depth == 0)
1433 if (iln->depth == 0)
1436 retidx = iln->varmap[o_iptr->s1.varindex];
1437 if (iln->n_resultlocal != -1) {
1438 /* store result in a local variable */
1440 DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
1441 /* This relies on the same sequence of types for */
1442 /* ?STORE and ?RETURN opcodes. */
1443 n_iptr->opc = ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN);
1444 n_iptr->s1.varindex = retidx;
1445 n_iptr->dst.varindex = iln->n_resultlocal;
1446 n_iptr->sx.s23.s3.javaindex = UNUSED; /* XXX set real javaindex? */
1451 n_iptr = (iln->inlined_iinstr_cursor++);
1452 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1455 else if ((retidx < resultjd->localcount && iln->blockafter)
1456 || !iln->blockafter) /* XXX do we really always need the MOVE? */
1458 /* local must not become outvar, insert a MOVE */
1460 n_iptr->opc = ICMD_MOVE;
1461 n_iptr->s1.varindex = retidx;
1462 retidx = inline_new_temp_variable(resultjd,
1463 resultjd->var[retidx].type);
1464 n_iptr->dst.varindex = retidx;
1466 n_iptr = (iln->inlined_iinstr_cursor++);
1467 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1471 if (iln->blockafter) {
1472 n_iptr->opc = ICMD_GOTO;
1473 n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
1474 inline_add_block_reference(iln, &(n_iptr->dst.block));
1477 n_iptr->opc = ICMD_NOP;
1481 if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
1482 n_iptr->opc = ICMD_NOP;
1491 inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
1494 DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
1503 /* end of basic block */
1505 if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
1506 close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
1507 n_bptr->icount = icount;
1509 DOLOG( printf("closed body block:\n");
1510 show_basicblock(resultjd, n_bptr, SHOW_STACK); );
1513 n_bptr->icount = icount;
1514 assert(iln->parent);
1515 if (retidx != UNUSED)
1516 iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
1520 bm = iln->ctx->blockmap;
1521 for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
1522 assert(bm->iln && bm->o_block && bm->n_block);
1524 inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block);
1527 #if !defined(NDEBUG)
1529 inline_target_ref *ref;
1532 if (!iln->depth || *(ref->ref) != INLINE_RETURN_REFERENCE(iln)) {
1533 DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
1534 (void*)*(ref->ref)) );
1544 static exception_entry * inline_exception_tables(inline_node *iln,
1545 exception_entry *n_extable,
1546 exception_entry **prevextable)
1550 exception_entry *et;
1554 assert(prevextable);
1556 child = iln->children;
1559 n_extable = inline_exception_tables(child, n_extable, prevextable);
1560 child = child->next;
1561 } while (child != iln->children);
1564 et = iln->jd->exceptiontable;
1565 for (; et != NULL; et = et->down) {
1567 MZERO(n_extable, exception_entry, 1);
1568 n_extable->start = inline_map_block(iln, et->start , iln);
1569 n_extable->end = inline_map_block(iln, et->end , iln);
1570 n_extable->handler = inline_map_block(iln, et->handler, iln);
1571 n_extable->catchtype = et->catchtype;
1574 (*prevextable)->down = n_extable;
1576 *prevextable = n_extable;
1581 if (iln->handler_monitorexit) {
1582 exception_entry **activehandlers;
1584 MZERO(n_extable, exception_entry, 1);
1585 n_extable->start = iln->inlined_basicblocks;
1586 n_extable->end = iln->inlined_basicblocks_cursor;
1587 n_extable->handler = iln->handler_monitorexit;
1588 n_extable->catchtype.any = NULL; /* finally */
1591 (*prevextable)->down = n_extable;
1593 *prevextable = n_extable;
1597 /* We have to protect the created handler with the same handlers */
1598 /* that protect the method body itself. */
1600 for (scope = iln; scope->parent != NULL; scope = scope->parent) {
1602 activehandlers = scope->o_handlers;
1603 assert(activehandlers);
1605 while (*activehandlers) {
1607 assert(scope->parent);
1609 MZERO(n_extable, exception_entry, 1);
1610 n_extable->start = iln->handler_monitorexit;
1611 n_extable->end = iln->handler_monitorexit + 1; /* XXX ok in this case? */
1612 n_extable->handler = inline_map_block(scope->parent,
1613 (*activehandlers)->handler,
1615 n_extable->catchtype = (*activehandlers)->catchtype;
1618 (*prevextable)->down = n_extable;
1620 *prevextable = n_extable;
1632 static void inline_locals(inline_node *iln)
1638 iln->varmap = create_variable_map(iln);
1640 child = iln->children;
1643 inline_locals(child);
1644 child = child->next;
1645 } while (child != iln->children);
1648 if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
1649 iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
1650 if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
1651 iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
1652 if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
1653 iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
1657 static void inline_interface_variables(inline_node *iln)
1664 resultjd = iln->ctx->resultjd;
1666 resultjd->interface_map = DMNEW(interface_info, 5*iln->ctx->maxinoutdepth);
1667 for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
1668 resultjd->interface_map[i].flags = UNUSED;
1670 for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
1671 assert(bptr->indepth <= iln->ctx->maxinoutdepth);
1672 assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
1674 for (i=0; i<bptr->indepth; ++i) {
1675 v = &(resultjd->var[bptr->invars[i]]);
1677 v->flags &= ~PREALLOC;
1678 v->flags &= ~INMEMORY;
1679 assert(bptr->invars[i] >= resultjd->localcount);
1681 if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1682 resultjd->interface_map[5*i + v->type].flags = v->flags;
1685 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1689 for (i=0; i<bptr->outdepth; ++i) {
1690 v = &(resultjd->var[bptr->outvars[i]]);
1692 v->flags &= ~PREALLOC;
1693 v->flags &= ~INMEMORY;
1694 assert(bptr->outvars[i] >= resultjd->localcount);
1696 if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1697 resultjd->interface_map[5*i + v->type].flags = v->flags;
1700 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1707 static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
1712 builtintable_entry *bte;
1717 child = iln->children;
1720 inline_write_exception_handlers(master, child);
1721 child = child->next;
1722 } while (child != iln->children);
1725 if (iln->synchronize) {
1726 /* create the monitorexit handler */
1727 n_bptr = create_block(master, iln, iln, NULL, NULL,
1728 iln->n_passthroughcount + 1);
1729 n_bptr->type = BBTYPE_EXH;
1730 n_bptr->flags = BBFINISHED;
1732 exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1733 n_bptr->invars[iln->n_passthroughcount] = exvar;
1735 iln->handler_monitorexit = n_bptr;
1737 /* ACONST / ALOAD */
1739 n_ins = master->inlined_iinstr_cursor++;
1740 if (iln->m->flags & ACC_STATIC) {
1741 n_ins->opc = ICMD_ACONST;
1742 n_ins->sx.val.c.cls = iln->m->class;
1743 n_ins->flags.bits = INS_FLAG_CLASS;
1746 n_ins->opc = ICMD_ALOAD;
1747 n_ins->s1.varindex = iln->synclocal;
1748 assert(n_ins->s1.varindex != UNUSED);
1750 /* XXX could be PREALLOCed for builtin call */
1751 syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1752 n_ins->dst.varindex = syncvar;
1757 bte = builtintable_get_internal(LOCK_monitor_exit);
1759 n_ins = master->inlined_iinstr_cursor++;
1760 n_ins->opc = ICMD_BUILTIN;
1761 n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
1762 n_ins->sx.s23.s2.args = DMNEW(s4, n_ins->s1.argcount);
1763 n_ins->sx.s23.s2.args[0] = syncvar;
1764 for (i=0; i < iln->n_passthroughcount + 1; ++i) {
1765 n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
1767 n_ins->sx.s23.s3.bte = bte;
1772 n_ins = master->inlined_iinstr_cursor++;
1773 n_ins->opc = ICMD_ATHROW;
1774 n_ins->flags.bits = 0;
1775 n_ins->s1.varindex = exvar;
1778 /* close basic block */
1780 close_block(iln, iln, n_bptr, iln->n_passthroughcount);
1786 /* second pass driver *********************************************************/
1788 static bool test_inlining(inline_node *iln, jitdata *jd,
1794 exception_entry *n_ext;
1795 exception_entry *prevext;
1801 #if !defined(NDEBUG)
1802 static int debug_verify_inlined_code = 1; /* XXX */
1803 static int debug_compile_inlined_code_counter = 0;
1806 DOLOG( dump_inline_tree(iln, 0); );
1808 assert(iln && jd && resultjd);
1812 n_ins = DMNEW(instruction, iln->cumul_instructioncount);
1813 MZERO(n_ins, instruction, iln->cumul_instructioncount);
1814 iln->inlined_iinstr = n_ins;
1816 n_bb = DMNEW(basicblock, iln->cumul_basicblockcount);
1817 MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
1818 iln->inlined_basicblocks = n_bb;
1820 iln->ctx->blockmap = DMNEW(inline_block_map, iln->cumul_blockmapcount);
1822 n_jd = jit_jitdata_new(iln->m);
1823 n_jd->flags = jd->flags;
1824 iln->ctx->resultjd = n_jd;
1828 /* create the local_map */
1830 n_jd->local_map = DMNEW(s4, 5*iln->cumul_maxlocals);
1831 for (i=0; i<5*iln->cumul_maxlocals; ++i)
1832 n_jd->local_map[i] = UNUSED;
1834 /* create / coalesce local variables */
1842 n_jd->localcount = n_jd->vartop;
1844 /* extra variables for verification (DEBUG) */
1846 #if !defined(NDEBUG)
1847 if (debug_verify_inlined_code) {
1848 n_jd->vartop += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
1849 if (n_jd->vartop > n_jd->varcount) {
1851 n_jd->var = DMREALLOC(n_jd->var, varinfo, n_jd->varcount, n_jd->vartop);
1852 n_jd->varcount = n_jd->vartop;
1857 /* write inlined code */
1859 rewrite_method(iln);
1861 /* create exception handlers */
1863 inline_write_exception_handlers(iln, iln);
1865 /* write the dummy end block */
1867 n_bptr = create_block(iln, iln, iln, NULL, NULL, 0);
1868 n_bptr->flags = BBUNDEF;
1869 n_bptr->type = BBTYPE_STD;
1871 /* store created code in jitdata */
1873 n_jd->basicblocks = iln->inlined_basicblocks;
1874 n_jd->basicblockindex = NULL;
1875 n_jd->instructioncount = iln->cumul_instructioncount;
1876 n_jd->instructions = iln->inlined_iinstr;
1878 /* link the basic blocks (dummy end block is not counted) */
1880 n_jd->basicblockcount = (iln->inlined_basicblocks_cursor - iln->inlined_basicblocks) - 1;
1881 for (i=0; i<n_jd->basicblockcount + 1; ++i)
1882 n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
1884 n_jd->basicblocks[i-1].next = NULL;
1886 /* check basicblock numbers */
1888 #if !defined(NDEBUG)
1889 jit_check_basicblock_numbers(n_jd);
1892 /* create the exception table */
1894 if (iln->cumul_exceptiontablelength) {
1895 exception_entry *tableend;
1897 n_ext = DMNEW(exception_entry, iln->cumul_exceptiontablelength);
1899 tableend = inline_exception_tables(iln, n_ext, &prevext);
1900 assert(tableend == n_ext + iln->cumul_exceptiontablelength);
1902 prevext->down = NULL;
1904 n_jd->exceptiontablelength = iln->cumul_exceptiontablelength;
1905 n_jd->exceptiontable = n_ext;
1911 /*******************************************************************************/
1914 memcpy(n_cd, jd->cd, sizeof(codegendata));
1916 n_cd->method = NULL; /* XXX */
1917 n_jd->maxlocals = iln->cumul_maxlocals;
1918 n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
1920 inline_post_process(n_jd);
1922 inline_interface_variables(iln);
1924 #if defined(ENABLE_VERIFIER) && !defined(NDEBUG)
1925 if (debug_verify_inlined_code) {
1926 debug_verify_inlined_code = 0;
1927 DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
1928 if (!typecheck(n_jd)) {
1929 *exceptionptr = NULL;
1930 DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
1934 DOLOG( printf("VERIFICATION PASSED.\n") );
1936 debug_verify_inlined_code = 1;
1938 #endif /* defined(ENABLE_VERIFIER) */
1940 /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
1942 n_jd->rd->freemem = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
1943 #if defined(HAS_4BYTE_STACKSLOT)
1944 n_jd->rd->freemem_2 = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
1947 #if !defined(NDEBUG)
1948 if (n_jd->instructioncount >= inline_debug_min_size
1949 && n_jd->instructioncount <= inline_debug_max_size)
1951 if (debug_compile_inlined_code_counter >= inline_debug_start_counter
1952 && debug_compile_inlined_code_counter <= inline_debug_end_counter)
1957 #if !defined(NDEBUG)
1958 inline_count_methods++;
1960 /* inline_debug_log++; */
1962 printf("==== %d.INLINE ==================================================================\n", debug_compile_inlined_code_counter);
1963 printf("\ninline tree:\n");
1964 dump_inline_tree(iln, 0);
1965 n_jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE | JITDATA_FLAG_SHOWDISASSEMBLE;
1966 /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
1967 printf("-------- DONE -----------------------------------------------------------\n");
1970 /* inline_debug_log--; */
1974 #if !defined(NDEBUG)
1975 debug_compile_inlined_code_counter++;
1982 /* first pass: build inlining tree ********************************************/
1984 static bool inline_analyse_callee(inline_node *caller,
1986 basicblock *callerblock,
1987 instruction *calleriptr,
1989 exception_entry **handlers,
1992 inline_node *cn; /* the callee inline_node */
1998 /* create an inline tree node */
2000 cn = DNEW(inline_node);
2001 MZERO(cn, inline_node, 1);
2003 cn->ctx = caller->ctx;
2005 cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
2006 isstatic = (callee->flags & ACC_STATIC);
2008 /* get the intermediate representation of the callee */
2010 if (!inline_jit_compile(cn))
2013 /* info about the call site */
2015 cn->depth = caller->depth + 1;
2016 cn->callerblock = callerblock;
2017 cn->callerins = calleriptr;
2018 cn->callerpc = callerpc;
2019 cn->o_handlers = handlers;
2020 cn->n_handlercount = caller->n_handlercount + nhandlers;
2022 /* determine if we need basic block boundaries before/after */
2024 cn->blockbefore = false;
2025 cn->blockafter = false;
2027 if (cn->jd->branchtoentry)
2028 cn->blockbefore = true;
2030 if (cn->jd->branchtoend)
2031 cn->blockafter = true;
2033 if (cn->jd->returncount > 1)
2034 cn->blockafter = true;
2036 /* XXX make safer and reusable (maybe store last real block) */
2037 for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
2040 if (cn->jd->returnblock != bptr)
2041 cn->blockafter = true;
2043 /* info about the callee */
2045 cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
2046 cn->prolog_instructioncount = callee->parseddesc->paramcount + 1;
2047 cn->epilog_instructioncount = 1; /* INLINE_END */
2048 cn->extra_instructioncount = 0;
2050 /* we need a CHECKNULL for instance methods */
2053 cn->prolog_instructioncount += 1;
2055 /* deal with synchronized callees */
2057 if (cn->synchronize) {
2059 builtintable_entry *bte;
2061 /* we need basic block boundaries because of the handler */
2063 cn->blockbefore = true;
2064 cn->blockafter = true;
2066 /* for synchronized static methods */
2067 /* we need an ACONST, MONITORENTER in the prolog */
2068 /* and ACONST, MONITOREXIT in the epilog */
2070 /* for synchronized instance methods */
2071 /* we need an COPY, MONITORENTER in the prolog */
2072 /* and MONITOREXIT in the epilog */
2075 cn->prolog_instructioncount += 2;
2076 cn->epilog_instructioncount += 2;
2079 cn->prolog_instructioncount += 2;
2080 cn->epilog_instructioncount += 1;
2081 cn->localsoffset += 1;
2084 /* and exception handler */
2085 /* ALOAD, builtin_monitorexit, ATHROW */
2087 cn->extra_instructioncount += 3;
2089 /* exception table entries */
2091 caller->cumul_exceptiontablelength += 1 + cn->n_handlercount;
2093 /* we must call the builtins */
2095 bte = builtintable_get_internal(LOCK_monitor_enter);
2097 if (md->memuse > cn->regdata->memuse)
2098 cn->regdata->memuse = md->memuse;
2099 if (md->argintreguse > cn->regdata->argintreguse)
2100 cn->regdata->argintreguse = md->argintreguse;
2102 bte = builtintable_get_internal(LOCK_monitor_exit);
2104 if (md->memuse > cn->regdata->memuse)
2105 cn->regdata->memuse = md->memuse;
2106 if (md->argintreguse > cn->regdata->argintreguse)
2107 cn->regdata->argintreguse = md->argintreguse;
2109 caller->ctx->calls_others = true;
2112 /* determine pass-through variables */
2114 i = calleriptr->s1.argcount - callee->parseddesc->paramcount; /* max # of pass-though vars */
2116 cn->n_passthroughvars = DMNEW(s4, i);
2118 for (argi = calleriptr->s1.argcount - 1; argi >= callee->parseddesc->paramcount; --argi) {
2119 s4 idx = calleriptr->sx.s23.s2.args[argi];
2120 if (idx >= caller->jd->localcount) {
2121 cn->n_passthroughvars[j] = idx;
2125 DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
2129 cn->n_selfpassthroughcount = j;
2130 cn->n_passthroughcount = caller->n_passthroughcount + cn->n_selfpassthroughcount;
2132 /* insert the node into the inline tree */
2134 insert_inline_node(caller, cn);
2136 /* analyse recursively */
2138 if (!inline_inline_intern(callee, cn))
2141 /* subtract one block if we continue the caller block */
2143 if (!cn->blockbefore)
2144 cn->cumul_basicblockcount -= 1;
2146 /* add exception handler block for synchronized callees */
2148 if (cn->synchronize) {
2149 caller->ctx->master->cumul_basicblockcount++;
2150 caller->ctx->master->cumul_blockmapcount++;
2153 /* cumulate counters */
2155 caller->cumul_instructioncount += cn->prolog_instructioncount;
2156 caller->cumul_instructioncount += cn->epilog_instructioncount;
2157 caller->cumul_instructioncount += cn->extra_instructioncount;
2158 caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
2160 caller->cumul_basicblockcount += cn->cumul_basicblockcount;
2161 caller->cumul_blockmapcount += cn->cumul_blockmapcount;
2162 caller->cumul_exceptiontablelength += cn->cumul_exceptiontablelength;
2163 if (cn->cumul_maxlocals > caller->cumul_maxlocals)
2164 caller->cumul_maxlocals = cn->cumul_maxlocals;
2166 if (caller->cumul_basicblockcount > 10*caller->ctx->master->jd->basicblockcount) {
2168 printf("STOPPING to avoid code explosion (%d blocks)\n",
2169 caller->cumul_basicblockcount);
2174 /* XXX extra block after inlined call */
2175 if (cn->blockafter) {
2176 caller->cumul_basicblockcount += 1;
2177 caller->cumul_blockmapcount += 1;
2184 static bool inline_inline_intern(methodinfo *m, inline_node *iln)
2189 int opcode; /* invocation opcode */
2191 inline_node *active;
2192 exception_entry **handlers;
2193 exception_entry *ex;
2202 /* initialize cumulative counters */
2204 iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
2205 iln->cumul_exceptiontablelength += mjd->exceptiontablelength;
2207 /* iterate over basic blocks */
2209 for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
2211 /* ignore dummy end blocks (but count them for the blockmap) */
2213 iln->cumul_blockmapcount++;
2214 if (bptr->icount > 0 || bptr->next != NULL)
2215 iln->cumul_basicblockcount++;
2217 /* skip dead code */
2219 if (bptr->flags < BBREACHED)
2222 /* allocate the buffer of active exception handlers */
2223 /* XXX this wastes some memory, but probably it does not matter */
2225 handlers = DMNEW(exception_entry*, mjd->exceptiontablelength + 1);
2227 /* determine the active exception handlers for this block */
2228 /* XXX maybe the handlers of a block should be part of our IR */
2229 /* XXX this should share code with the type checkers */
2231 for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
2232 if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
2233 handlers[nhandlers++] = ex;
2236 handlers[nhandlers] = NULL;
2239 iptr = bptr->iinstr;
2241 iln->instructioncount += len;
2242 iln->cumul_instructioncount += len;
2244 for (; --len >= 0; ++iptr) {
2249 /****************************************/
2252 case ICMD_INVOKEVIRTUAL:
2253 case ICMD_INVOKESPECIAL:
2254 case ICMD_INVOKESTATIC:
2255 case ICMD_INVOKEINTERFACE:
2257 if (!INSTRUCTION_IS_UNRESOLVED(iptr)) {
2258 callee = iptr->sx.s23.s3.fmiref->p.method;
2262 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Code_Table") == 0
2263 && (strcmp(callee->name->text, "of") == 0
2264 || strcmp(callee->name->text, "set") == 0))
2266 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Compressor") == 0
2267 && (strcmp(callee->name->text, "output") == 0))
2269 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Decompressor") == 0
2270 && (strcmp(callee->name->text, "getcode") == 0))
2272 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Output_Buffer") == 0
2273 && (strcmp(callee->name->text, "putbyte") == 0))
2275 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Input_Buffer") == 0
2276 && (strcmp(callee->name->text, "getbyte") == 0
2277 || strcmp(callee->name->text, "readbytes") == 0
2282 if (callee->jcodelength > 0)
2286 if (callee->flags & ACC_NATIVE)
2289 if (iln->depth >= 3)
2292 if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
2293 || opcode == ICMD_INVOKESPECIAL)) {
2294 speculative = false;
2298 /* XXX search single implementation for abstract monomorphics */
2299 if ((callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED
2301 == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED)) {
2304 DOLOG( printf("SPECULATIVE INLINE: "); method_println(callee); );
2310 /* polymorphic call site */
2314 for (active = iln; active; active = active->parent) {
2315 if (callee == active->m) {
2316 DOLOG( printf("RECURSIVE!\n") );
2323 if (!inline_analyse_callee(iln, callee,
2326 iln->instructioncount - len - 1 /* XXX ugly */,
2332 method_add_assumption_monomorphic(callee, iln->ctx->master->m);
2343 /* extra ICMD_MOVE may be necessary */
2344 iln->cumul_instructioncount++;
2349 /* end of basic block */
2356 /* post processing ************************************************************/
2358 #define POSTPROCESS_SRC(varindex) live[varindex]--
2359 #define POSTPROCESS_DST(varindex) live[varindex]++
2361 #define POSTPROCESS_SRCOP(s) POSTPROCESS_SRC(iptr->s.varindex)
2362 #define POSTPROCESS_DSTOP(d) POSTPROCESS_DST(iptr->d.varindex)
2364 #define MARKSAVED(varindex) jd->var[varindex].flags |= SAVEDVAR
2366 #define MARK_ALL_SAVED \
2368 for (i=0; i<jd->vartop; ++i) \
2373 static void inline_post_process(jitdata *jd)
2379 icmdtable_entry_t *icmdt;
2382 builtintable_entry *bte;
2384 /* reset the SAVEDVAR flag of all variables */
2386 for (i=0; i<jd->vartop; ++i)
2387 jd->var[i].flags &= ~SAVEDVAR;
2389 /* allocate the life counters */
2391 live = DMNEW(s4, jd->vartop);
2392 MZERO(live, s4, jd->vartop);
2394 /* iterate over all basic blocks */
2396 for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
2397 if (bptr->flags < BBREACHED)
2400 /* make invars live */
2402 for (i=0; i<bptr->indepth; ++i)
2403 POSTPROCESS_DST(bptr->invars[i]);
2405 iptr = bptr->iinstr;
2406 iend = iptr + bptr->icount;
2408 for (; iptr < iend; ++iptr) {
2410 icmdt = &(icmd_table[iptr->opc]);
2412 switch (icmdt->dataflow) {
2414 POSTPROCESS_SRCOP(sx.s23.s3);
2416 POSTPROCESS_SRCOP(sx.s23.s2);
2418 POSTPROCESS_SRCOP(s1);
2420 if (icmdt->flags & ICMDTABLE_CALLS) {
2421 jd->isleafmethod = false;
2427 POSTPROCESS_SRCOP(sx.s23.s2);
2430 POSTPROCESS_SRCOP(s1);
2432 if (icmdt->flags & ICMDTABLE_CALLS) {
2433 jd->isleafmethod = false;
2437 POSTPROCESS_DSTOP(dst);
2441 for (i=0; i<iptr->s1.argcount; ++i) {
2442 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
2444 if (icmdt->flags & ICMDTABLE_CALLS) {
2445 jd->isleafmethod = false;
2448 POSTPROCESS_DSTOP(dst);
2452 INSTRUCTION_GET_METHODDESC(iptr, md);
2454 jd->isleafmethod = false;
2455 for (i=0; i<md->paramcount; ++i) {
2456 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
2458 for (; i<iptr->s1.argcount; ++i) {
2459 MARKSAVED(iptr->sx.s23.s2.args[i]);
2461 if (md->returntype.type != TYPE_VOID)
2462 POSTPROCESS_DSTOP(dst);
2466 bte = iptr->sx.s23.s3.bte;
2468 goto post_process_call;
2474 } /* end instruction loop */
2476 /* consume outvars */
2478 for (i=0; i<bptr->outdepth; ++i)
2479 POSTPROCESS_SRC(bptr->outvars[i]);
2481 #if !defined(NDEBUG)
2482 for (i=jd->localcount; i < jd->vartop; ++i)
2483 assert(live[i] == 0);
2486 } /* end basic block loop */
2490 /* main driver function *******************************************************/
2492 bool inline_inline(jitdata *jd, jitdata **resultjd)
2501 DOLOG( printf("==== INLINE ==================================================================\n");
2502 show_method(jd, SHOW_STACK); );
2504 iln = DNEW(inline_node);
2505 MZERO(iln, inline_node, 1);
2507 iln->ctx = DNEW(inline_context);
2508 MZERO(iln->ctx, inline_context, 1);
2509 iln->ctx->master = iln;
2510 iln->ctx->calls_others = false;
2513 iln->regdata = jd->rd;
2514 iln->ctx->next_debugnr = 1; /* XXX debug */
2516 iln->blockbefore = true;
2517 iln->blockafter = true;
2519 /* we cannot use m->instructioncount because it may be greater than
2520 * the actual number of instructions in the basic blocks. */
2521 iln->instructioncount = 0;
2522 iln->cumul_instructioncount = 0;
2523 iln->cumul_basicblockcount = 1 /* dummy end block */;
2525 if (inline_inline_intern(m, iln)) {
2527 DOLOG( printf("==== TEST INLINE =============================================================\n"); );
2530 test_inlining(iln, jd, resultjd);
2533 DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
2540 * These are local overrides for various environment variables in Emacs.
2541 * Please do not remove this and leave it at the end of the file, where
2542 * Emacs will automagically detect them.
2543 * ---------------------------------------------------------------------
2546 * indent-tabs-mode: t
2550 * vim:noexpandtab:sw=4:ts=4: