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 6262 2006-12-31 17:57:22Z 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;
167 struct inline_block_map {
173 struct inline_context {
178 int next_block_number;
179 inline_block_map *blockmap;
186 int next_debugnr; /* XXX debug */
190 /* prototypes *****************************************************************/
192 static bool inline_inline_intern(methodinfo *m, inline_node *iln);
193 static void inline_post_process(jitdata *jd);
196 /* debug helpers **************************************************************/
199 #include "inline_debug.inc"
201 void inline_print_stats()
203 printf("inlined callers: %d\n", inline_count_methods);
208 /* compilation of callees *****************************************************/
210 static bool inline_jit_compile_intern(jitdata *jd)
214 /* XXX should share code with jit.c */
218 /* XXX initialize the static function's class */
222 /* call the compiler passes ***********************************************/
224 /* call parse pass */
226 DOLOG( log_message_class("Parsing ", m->class) );
231 /* call stack analysis pass */
233 if (!stack_analyse(jd)) {
241 static bool inline_jit_compile(inline_node *iln)
247 /* XXX should share code with jit.c */
253 #if defined(ENABLE_THREADS)
254 /* enter a monitor on the method */
255 lock_monitor_enter((java_objectheader *) m);
258 /* allocate jitdata structure and fill it */
260 jd = jit_jitdata_new(m);
263 jd->flags = 0; /* XXX */
265 /* initialize the register allocator */
269 /* setup the codegendata memory */
271 /* XXX do a pseudo setup */
272 jd->cd = DNEW(codegendata);
273 MZERO(jd->cd, codegendata, 1);
274 jd->cd->maxstack = m->maxstack;
276 /* XXX uses too much dump memory codegen_setup(jd); */
278 /* now call internal compile function */
280 r = inline_jit_compile_intern(jd);
283 iln->regdata = jd->rd;
286 /* free some memory */
289 #if defined(ENABLE_JIT)
290 # if defined(ENABLE_INTRP)
298 #if defined(ENABLE_THREADS)
299 /* leave the monitor */
300 lock_monitor_exit((java_objectheader *) m );
307 /* inlining tree handling *****************************************************/
309 static void insert_inline_node(inline_node *parent, inline_node *child)
314 assert(parent && child);
316 child->parent = parent;
318 child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
320 first = parent->children;
322 /* insert as only node */
323 parent->children = child;
329 /* {there is at least one child already there} */
331 /* XXX is this search necessary, or could we always add at the end? */
334 while (succ->callerpc < child->callerpc) {
337 /* insert as last node */
338 child->prev = first->prev;
340 child->prev->next = child;
341 child->next->prev = child;
346 assert(succ->callerpc > child->callerpc);
348 /* insert before succ */
350 child->prev = succ->prev;
352 child->prev->next = child;
353 child->next->prev = child;
357 /* variable handling **********************************************************/
359 static s4 inline_new_variable(jitdata *jd, s4 type, s4 flags)
364 index = jd->vartop++;
365 if (index >= jd->varcount) {
366 newcount = jd->vartop * 2; /* XXX */
367 jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, newcount);
368 MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
369 jd->varcount = newcount;
372 jd->var[index].type = type;
373 jd->var[index].flags = flags;
379 static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
384 v = &(origjd->var[origidx]);
386 newidx = inline_new_variable(jd, v->type, v->flags);
388 jd->var[newidx].vv = v->vv;
394 static s4 inline_new_temp_variable(jitdata *jd, s4 type)
396 return inline_new_variable(jd, type, 0);
400 static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
407 idx = inline_new_variable_clone(jd, origjd, index);
415 static s4 *create_variable_map(inline_node *callee)
424 /* create the variable mapping */
426 varmap = DMNEW(s4, callee->jd->varcount);
427 for (i=0; i<callee->jd->varcount; ++i)
430 /* translate local variables */
432 for (i=0; i<callee->m->maxlocals; ++i) {
433 for (t=0; t<5; ++t) {
434 idx = callee->jd->local_map[5*i + t];
438 v = &(callee->jd->var[idx]);
439 assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
440 v->type = t; /* XXX restore if it is TYPE_VOID */
442 avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
444 if (avail == UNUSED) {
445 avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, idx);
446 callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
453 /* for synchronized instance methods we need an extra local */
455 if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
456 n_idx = callee->localsoffset - 1;
458 assert(callee->parent);
459 assert(n_idx == callee->parent->localsoffset + callee->parent->m->maxlocals);
461 avail = callee->ctx->resultjd->local_map[5*n_idx + TYPE_ADR];
463 if (avail == UNUSED) {
464 avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
465 callee->ctx->resultjd->local_map[5*n_idx + TYPE_ADR] = avail;
468 callee->synclocal = avail;
471 callee->synclocal = UNUSED;
478 /* basic block translation ****************************************************/
480 #define INLINE_RETURN_REFERENCE(callee) \
481 ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
483 #define RETADDRNR_FROM_BLOCK(bptr) (UNUSED - 1 - (bptr)->nr)
486 static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
488 inline_target_ref *ref;
490 ref = DNEW(inline_target_ref);
491 ref->ref.block = blockp;
492 ref->isnumber = false;
493 ref->next = iln->refs;
498 static void inline_add_blocknr_reference(inline_node *iln, s4 *nrp)
500 inline_target_ref *ref;
502 ref = DNEW(inline_target_ref);
504 ref->isnumber = true;
505 ref->next = iln->refs;
510 static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
515 assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
517 ctx->blockmap[ctx->blockmap_index].iln = iln;
518 ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
519 ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
521 ctx->blockmap_index++;
525 static basicblock * inline_map_block(inline_node *iln,
527 inline_node *targetiln)
529 inline_block_map *bm;
530 inline_block_map *bmend;
538 bm = iln->ctx->blockmap;
539 bmend = bm + iln->ctx->blockmap_index;
542 assert(bm->iln && bm->o_block && bm->n_block);
543 if (bm->o_block == o_block && bm->iln == targetiln)
549 return NULL; /* not reached */
553 static void inline_resolve_block_refs(inline_target_ref **refs,
558 inline_target_ref *ref;
559 inline_target_ref *prev;
562 for (ref = *refs; ref != NULL; ref = ref->next) {
563 if (ref->isnumber && !returnref) {
564 if (*(ref->ref.nr) == RETADDRNR_FROM_BLOCK(o_bptr)) {
565 *(ref->ref.nr) = RETADDRNR_FROM_BLOCK(n_bptr);
570 if (*(ref->ref.block) == o_bptr) {
571 *(ref->ref.block) = n_bptr;
582 /* remove this ref */
585 prev->next = ref->next;
594 /* basic block creation *******************************************************/
596 static basicblock * create_block(inline_node *container,
611 assert(indepth >= 0);
613 n_bptr = container->inlined_basicblocks_cursor++;
615 assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
617 BASICBLOCK_INIT(n_bptr, iln->m);
619 n_bptr->iinstr = container->inlined_iinstr_cursor;
620 n_bptr->next = n_bptr + 1;
621 n_bptr->nr = container->ctx->next_block_number++;
622 n_bptr->indepth = indepth;
623 n_bptr->flags = BBFINISHED; /* XXX */
625 /* set the inlineinfo of the new block */
627 if (iln->inline_start_instruction)
628 n_bptr->inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
630 if (indepth > container->ctx->maxinoutdepth)
631 container->ctx->maxinoutdepth = indepth;
634 n_bptr->invars = DMNEW(s4, indepth);
637 for (i=0; i<indepth; ++i)
638 n_bptr->invars[i] = -1; /* XXX debug */
640 /* pass-through variables enter the block */
642 outer = inner->parent;
643 while (outer != NULL) {
644 depth = outer->n_passthroughcount;
646 assert(depth + inner->n_selfpassthroughcount <= indepth);
648 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
649 varidx = inner->n_passthroughvars[i];
651 inline_new_variable_clone(container->ctx->resultjd,
654 n_bptr->invars[depth + i] = newvaridx;
655 outer->varmap[varidx] = newvaridx;
658 outer = outer->parent;
662 n_bptr->invars = NULL;
665 /* XXX for the verifier. should not be here */
670 dv = DMNEW(varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
671 MZERO(dv, varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
672 n_bptr->inlocals = dv;
679 static s4 *translate_javalocals(inline_node *iln, s4 *javalocals)
684 jl = DMNEW(s4, iln->jd->maxlocals);
686 for (i=0; i<iln->jd->maxlocals; ++i) {
689 j = inline_translate_variable(iln->ctx->resultjd, iln->jd, iln->varmap, j);
694 /* an encoded returnAddress value - must be relocated */
695 inline_add_blocknr_reference(iln, &(jl[i]));
704 static basicblock * create_body_block(inline_node *iln,
705 basicblock *o_bptr, s4 *varmap)
710 n_bptr = create_block(iln, iln, iln,
711 o_bptr->indepth + iln->n_passthroughcount);
713 n_bptr->type = o_bptr->type;
714 n_bptr->flags = o_bptr->flags;
715 n_bptr->bitflags = o_bptr->bitflags;
717 /* resolve references to this block */
719 inline_resolve_block_refs(&(iln->refs), o_bptr, n_bptr, false);
721 /* translate the invars of the original block */
723 for (i=0; i<o_bptr->indepth; ++i) {
724 n_bptr->invars[iln->n_passthroughcount + i] =
725 inline_translate_variable(iln->ctx->resultjd, iln->jd,
730 /* translate javalocals info (not for dead code) */
732 if (n_bptr->flags >= BBREACHED)
733 n_bptr->javalocals = translate_javalocals(iln, o_bptr->javalocals);
739 static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
745 /* number of return variables */
747 retcount = (callee->n_resultlocal == -1
748 && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
750 /* start the epilog block */
752 n_bptr = create_block(caller, caller, callee,
753 callee->n_passthroughcount + retcount);
755 /* resolve references to the return block */
757 inline_resolve_block_refs(&(callee->refs),
758 INLINE_RETURN_REFERENCE(callee),
762 /* return variable */
765 idx = inline_new_variable(caller->ctx->resultjd,
766 callee->m->parseddesc->returntype.type, 0 /* XXX */);
767 n_bptr->invars[callee->n_passthroughcount] = idx;
768 varmap[callee->callerins->dst.varindex] = idx;
773 n_bptr->javalocals = DMNEW(s4, caller->jd->maxlocals);
774 MCOPY(n_bptr->javalocals, caller->javalocals, s4, caller->jd->maxlocals);
776 /* set block flags & type */
778 n_bptr->flags = /* XXX original block flags */ BBFINISHED;
779 n_bptr->type = BBTYPE_STD;
785 static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
792 n_bptr->outdepth = outdepth;
793 n_bptr->outvars = DMNEW(s4, outdepth);
795 for (i=0; i<outdepth; ++i)
796 n_bptr->outvars[i] = 0; /* XXX debug */
798 if (outdepth > iln->ctx->maxinoutdepth)
799 iln->ctx->maxinoutdepth = outdepth;
801 /* pass-through variables leave the block */
803 outer = inner->parent;
804 while (outer != NULL) {
805 depth = outer->n_passthroughcount;
807 assert(depth + inner->n_selfpassthroughcount <= outdepth);
809 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
810 varidx = inner->n_passthroughvars[i];
811 n_bptr->outvars[depth + i] =
812 inline_translate_variable(iln->ctx->resultjd,
818 outer = outer->parent;
823 static void close_prolog_block(inline_node *iln,
825 inline_node *nextcall)
827 /* XXX add original outvars! */
828 close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
830 /* pass-through variables */
832 DOLOG( printf("closed prolog block:\n");
833 show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
837 static void close_body_block(inline_node *iln,
846 close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
848 /* translate the outvars of the original block */
851 for (i=0; i<o_bptr->outdepth; ++i) {
852 n_bptr->outvars[iln->n_passthroughcount + i] =
853 inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
857 /* set the return variable, if any */
861 n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
866 /* inlined code generation ****************************************************/
868 static instruction * inline_instruction(inline_node *iln,
874 n_iptr = (iln->inlined_iinstr_cursor++);
875 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
877 n_iptr->opc = opcode;
878 n_iptr->flags.bits = o_iptr->flags.bits & INS_FLAG_ID_MASK;
879 n_iptr->line = o_iptr->line;
884 static void inline_generate_sync_builtin(inline_node *iln,
893 if (callee->m->flags & ACC_STATIC) {
895 syncvar = inline_new_temp_variable(iln->ctx->resultjd, TYPE_ADR);
897 n_ins = inline_instruction(iln, ICMD_ACONST, o_iptr);
898 n_ins->sx.val.c.cls = callee->m->class;
899 n_ins->dst.varindex = syncvar;
900 n_ins->flags.bits |= INS_FLAG_CLASS;
903 syncvar = instancevar;
906 assert(syncvar != UNUSED);
908 /* MONITORENTER / MONITOREXIT */
910 n_ins = inline_instruction(iln, ICMD_BUILTIN, o_iptr);
911 n_ins->sx.s23.s3.bte = builtintable_get_internal(func);
912 n_ins->s1.argcount = 1; /* XXX add through-vars */
913 n_ins->sx.s23.s2.args = DMNEW(s4, 1);
914 n_ins->sx.s23.s2.args[0] = syncvar;
917 static s4 emit_inlining_prolog(inline_node *iln,
929 insinfo_inline *insinfo;
932 assert(iln && callee && o_iptr);
935 md = calleem->parseddesc;
936 isstatic = (calleem->flags & ACC_STATIC);
938 /* INLINE_START instruction */
940 n_ins = inline_instruction(iln, ICMD_INLINE_START, o_iptr);
942 insinfo = DNEW(insinfo_inline);
943 insinfo->method = callee->m;
944 insinfo->outer = iln->m;
945 insinfo->synclocal = callee->synclocal;
946 insinfo->synchronize = callee->synchronize;
947 insinfo->javalocals_start = NULL;
948 insinfo->javalocals_end = NULL;
950 /* info about stack vars live at the INLINE_START */
952 insinfo->throughcount = callee->n_passthroughcount;
953 insinfo->paramcount = md->paramcount;
954 insinfo->stackvarscount = o_iptr->s1.argcount;
955 insinfo->stackvars = DMNEW(s4, insinfo->stackvarscount);
956 for (i=0; i<insinfo->stackvarscount; ++i)
957 insinfo->stackvars[i] = iln->varmap[o_iptr->sx.s23.s2.args[i]];
959 /* info about the surrounding inlining */
961 if (iln->inline_start_instruction)
962 insinfo->parent = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
964 insinfo->parent = NULL;
966 /* finish the INLINE_START instruction */
968 n_ins->sx.s23.s3.inlineinfo = insinfo;
969 callee->inline_start_instruction = n_ins;
971 DOLOG( printf("%sprolog: ", iln->indent);
972 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
974 /* handle parameters for the inlined callee */
976 localindex = callee->localsoffset + md->paramslots;
978 for (i=md->paramcount-1; i>=0; --i) {
981 type = md->paramtypes[i].type;
983 localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
984 assert(callee->regdata);
986 /* translate the argument variable */
988 argvar = varmap[o_iptr->sx.s23.s2.args[i]];
989 assert(argvar != UNUSED);
991 /* remove preallocation from the argument variable */
993 iln->ctx->resultjd->var[argvar].flags &= ~(PREALLOC | INMEMORY);
995 /* check the instance slot against NULL */
996 /* we don't need that for <init> methods, as the verifier */
997 /* ensures that they are only called for an uninit. object */
998 /* (which may not be NULL). */
1000 if (!isstatic && i == 0 && calleem->name != utf_init) {
1001 assert(type == TYPE_ADR);
1002 n_ins = inline_instruction(iln, ICMD_CHECKNULL, o_iptr);
1003 n_ins->s1.varindex = argvar;
1004 n_ins->dst.varindex = n_ins->s1.varindex;
1007 /* store argument into local variable of inlined callee */
1009 if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != UNUSED)
1011 /* this value is used in the callee */
1013 if (i == 0 && callee->synclocal != UNUSED) {
1014 /* we also need it for synchronization, so copy it */
1015 assert(type == TYPE_ADR);
1016 n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
1019 n_ins = inline_instruction(iln, ICMD_ISTORE + type, o_iptr);
1020 n_ins->sx.s23.s3.javaindex = UNUSED;
1022 n_ins->s1.varindex = argvar;
1023 n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
1024 assert(n_ins->dst.varindex != UNUSED);
1026 else if (i == 0 && callee->synclocal != UNUSED) {
1027 /* the value is not used inside the callee, but we need it for */
1028 /* synchronization */
1029 /* XXX In this case it actually makes no sense to create a */
1030 /* separate synchronization variable. */
1032 n_ins = inline_instruction(iln, ICMD_NOP, o_iptr);
1035 /* this value is not used, pop it */
1037 n_ins = inline_instruction(iln, ICMD_POP, o_iptr);
1038 n_ins->s1.varindex = argvar;
1041 DOLOG( printf("%sprolog: ", iln->indent);
1042 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1045 /* COPY for synchronized instance methods */
1047 if (callee->synclocal != UNUSED) {
1048 n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
1049 n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
1050 n_ins->dst.varindex = callee->synclocal;
1052 assert(n_ins->s1.varindex != UNUSED);
1055 if (callee->synchronize) {
1056 inline_generate_sync_builtin(iln, callee, o_iptr,
1057 (isstatic) ? UNUSED : varmap[o_iptr->sx.s23.s2.args[0]],
1058 LOCK_monitor_enter);
1061 /* INLINE_BODY instruction */
1063 n_ins = inline_instruction(iln, ICMD_INLINE_BODY, callee->jd->basicblocks[0].iinstr);
1064 n_ins->sx.s23.s3.inlineinfo = insinfo;
1070 static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
1075 assert(iln && callee && o_iptr);
1076 assert(callee->inline_start_instruction);
1078 if (callee->synchronize) {
1079 inline_generate_sync_builtin(iln, callee, o_iptr,
1084 /* INLINE_END instruction */
1086 n_ins = inline_instruction(iln, ICMD_INLINE_END, o_iptr);
1087 n_ins->sx.s23.s3.inlineinfo = callee->inline_start_instruction->sx.s23.s3.inlineinfo;
1089 /* set the javalocals */
1091 jl = DMNEW(s4, iln->jd->maxlocals);
1092 MCOPY(jl, iln->javalocals, s4, iln->jd->maxlocals);
1093 n_ins->sx.s23.s3.inlineinfo->javalocals_end = jl;
1095 DOLOG( printf("%sepilog: ", iln->indent);
1096 show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1100 #define TRANSLATE_VAROP(vo) \
1101 n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
1104 static void inline_clone_instruction(inline_node *iln,
1108 instruction *o_iptr,
1109 instruction *n_iptr)
1111 icmdtable_entry_t *icmdt;
1112 builtintable_entry *bte;
1115 branch_target_t *table;
1116 lookup_target_t *lookup;
1121 icmdt = &(icmd_table[o_iptr->opc]);
1123 switch (icmdt->dataflow) {
1128 TRANSLATE_VAROP(sx.s23.s3);
1130 TRANSLATE_VAROP(sx.s23.s2);
1132 TRANSLATE_VAROP(s1);
1136 TRANSLATE_VAROP(sx.s23.s2);
1140 TRANSLATE_VAROP(s1);
1142 TRANSLATE_VAROP(dst);
1146 n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1147 for (i=0; i<n_iptr->s1.argcount; ++i) {
1148 n_iptr->sx.s23.s2.args[i] =
1149 inline_translate_variable(jd, origjd, varmap,
1150 o_iptr->sx.s23.s2.args[i]);
1152 TRANSLATE_VAROP(dst);
1156 INSTRUCTION_GET_METHODDESC(n_iptr, md);
1158 n_iptr->s1.argcount += iln->n_passthroughcount;
1159 n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1160 for (i=0; i<o_iptr->s1.argcount; ++i) {
1161 n_iptr->sx.s23.s2.args[i] =
1162 inline_translate_variable(jd, origjd, varmap,
1163 o_iptr->sx.s23.s2.args[i]);
1165 for (scope = iln; scope != NULL; scope = scope->parent) {
1166 for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
1167 n_iptr->sx.s23.s2.args[i++] =
1168 scope->parent->varmap[scope->n_passthroughvars[j]];
1171 if (md->returntype.type != TYPE_VOID)
1172 TRANSLATE_VAROP(dst);
1176 bte = n_iptr->sx.s23.s3.bte;
1184 switch (icmdt->controlflow) {
1186 TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
1190 inline_add_block_reference(iln, &(n_iptr->dst.block));
1194 inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
1198 i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
1200 table = DMNEW(branch_target_t, i);
1201 MCOPY(table, o_iptr->dst.table, branch_target_t, i);
1202 n_iptr->dst.table = table;
1205 inline_add_block_reference(iln, &(table->block));
1211 inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
1213 i = n_iptr->sx.s23.s2.lookupcount;
1214 lookup = DMNEW(lookup_target_t, i);
1215 MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
1216 n_iptr->dst.lookup = lookup;
1219 inline_add_block_reference(iln, &(lookup->target.block));
1225 /* XXX move this to dataflow section? */
1227 switch (n_iptr->opc) {
1230 if (n_iptr->flags.bits & INS_FLAG_RETADDR)
1231 inline_add_blocknr_reference(iln, &(n_iptr->sx.s23.s2.retaddrnr));
1238 stack_javalocals_store(n_iptr, iln->javalocals);
1244 static void rewrite_method(inline_node *iln)
1248 instruction *o_iptr;
1249 instruction *n_iptr;
1250 inline_node *nextcall;
1252 inline_block_map *bm;
1257 char indent[100]; /* XXX debug */
1263 resultjd = iln->ctx->resultjd;
1267 nextcall = iln->children;
1270 for (i=0; i<iln->depth; ++i)
1273 iln->indent = indent;
1275 DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
1276 printf("%s(passthrough: %d+%d)\n",
1277 indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
1278 iln->n_passthroughcount); );
1280 /* set memory cursors */
1282 iln->inlined_iinstr_cursor = iln->inlined_iinstr;
1283 iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
1285 /* allocate temporary buffers */
1287 iln->javalocals = DMNEW(s4, iln->jd->maxlocals);
1289 /* loop over basic blocks */
1291 o_bptr = iln->jd->basicblocks;
1292 for (; o_bptr; o_bptr = o_bptr->next) {
1294 if (o_bptr->flags < BBREACHED) {
1296 /* ignore the dummy end block */
1298 if (o_bptr->icount == 0 && o_bptr->next == NULL) {
1299 /* enter the following block as translation, for exception handler ranges */
1300 inline_block_translation(iln, o_bptr, iln->inlined_basicblocks_cursor);
1305 printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
1307 o_bptr->nr, o_bptr->flags, o_bptr->type,
1309 method_println(iln->m);
1312 n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1314 /* enter it in the blockmap */
1316 inline_block_translation(iln, o_bptr, n_bptr);
1318 close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
1322 len = o_bptr->icount;
1323 o_iptr = o_bptr->iinstr;
1326 printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
1328 o_bptr->nr, o_bptr->flags, o_bptr->type,
1330 method_println(iln->m);
1331 show_basicblock(iln->jd, o_bptr, SHOW_STACK);
1334 if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
1335 /* create an inlined clone of this block */
1337 n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1340 /* enter it in the blockmap */
1342 inline_block_translation(iln, o_bptr, n_bptr);
1344 /* initialize the javalocals */
1346 MCOPY(iln->javalocals, n_bptr->javalocals, s4, iln->jd->maxlocals);
1351 /* continue caller block */
1353 n_bptr = iln->inlined_basicblocks_cursor - 1;
1354 icount = n_bptr->icount;
1356 /* translate the javalocals */
1358 jl = translate_javalocals(iln, o_bptr->javalocals);
1359 iln->inline_start_instruction->sx.s23.s3.inlineinfo->javalocals_start = jl;
1361 MCOPY(iln->javalocals, jl, s4, iln->jd->maxlocals);
1364 /* iterate over the ICMDs of this block */
1369 while (--len >= 0) {
1371 DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false, SHOW_STACK);
1374 /* handle calls that will be inlined */
1376 if (nextcall && o_iptr == nextcall->callerins) {
1378 /* write the inlining prolog */
1380 (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
1381 icount += nextcall->prolog_instructioncount;
1383 /* end current block, or glue blocks together */
1385 n_bptr->icount = icount;
1387 if (nextcall->blockbefore) {
1388 close_prolog_block(iln, n_bptr, nextcall);
1394 /* check if the result is a local variable */
1396 if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
1397 && o_iptr->dst.varindex < iln->jd->localcount)
1399 nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
1402 nextcall->n_resultlocal = -1;
1404 /* set memory pointers in the callee */
1406 nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
1407 nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
1411 DOLOG( printf("%sentering inline ", indent);
1412 show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1414 rewrite_method(nextcall);
1416 DOLOG( printf("%sleaving inline ", indent);
1417 show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1419 /* update memory cursors */
1421 assert(nextcall->inlined_iinstr_cursor
1422 <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
1423 assert(nextcall->inlined_basicblocks_cursor
1424 == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
1425 iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
1426 iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
1428 /* start new block, or glue blocks together */
1430 if (nextcall->blockafter) {
1431 n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
1435 n_bptr = iln->inlined_basicblocks_cursor - 1;
1436 icount = n_bptr->icount;
1440 /* emit inlining epilog */
1442 emit_inlining_epilog(iln, nextcall, o_iptr);
1443 icount += nextcall->epilog_instructioncount;
1445 /* proceed to next call */
1447 nextcall = nextcall->next;
1450 n_iptr = (iln->inlined_iinstr_cursor++);
1451 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1453 switch (o_iptr->opc) {
1455 if (iln->depth == 0)
1464 if (iln->depth == 0)
1467 retidx = iln->varmap[o_iptr->s1.varindex];
1468 if (iln->n_resultlocal != -1) {
1469 /* store result in a local variable */
1471 DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
1472 /* This relies on the same sequence of types for */
1473 /* ?STORE and ?RETURN opcodes. */
1474 n_iptr->opc = ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN);
1475 n_iptr->s1.varindex = retidx;
1476 n_iptr->dst.varindex = iln->n_resultlocal;
1477 n_iptr->sx.s23.s3.javaindex = UNUSED; /* XXX set real javaindex? */
1482 n_iptr = (iln->inlined_iinstr_cursor++);
1483 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1486 else if ((retidx < resultjd->localcount && iln->blockafter)
1487 || !iln->blockafter) /* XXX do we really always need the MOVE? */
1489 /* local must not become outvar, insert a MOVE */
1491 n_iptr->opc = ICMD_MOVE;
1492 n_iptr->s1.varindex = retidx;
1493 retidx = inline_new_temp_variable(resultjd,
1494 resultjd->var[retidx].type);
1495 n_iptr->dst.varindex = retidx;
1497 n_iptr = (iln->inlined_iinstr_cursor++);
1498 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1502 if (iln->blockafter) {
1503 n_iptr->opc = ICMD_GOTO;
1504 n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
1505 inline_add_block_reference(iln, &(n_iptr->dst.block));
1508 n_iptr->opc = ICMD_NOP;
1512 if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
1513 n_iptr->opc = ICMD_NOP;
1522 inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
1525 DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
1534 /* end of basic block */
1536 if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
1537 close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
1538 n_bptr->icount = icount;
1540 DOLOG( printf("closed body block:\n");
1541 show_basicblock(resultjd, n_bptr, SHOW_STACK); );
1544 n_bptr->icount = icount;
1545 assert(iln->parent);
1546 if (retidx != UNUSED)
1547 iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
1551 bm = iln->ctx->blockmap;
1552 for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
1553 assert(bm->iln && bm->o_block && bm->n_block);
1555 inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block, false);
1558 #if !defined(NDEBUG)
1560 inline_target_ref *ref;
1563 if (!iln->depth || ref->isnumber || *(ref->ref.block) != INLINE_RETURN_REFERENCE(iln)) {
1564 DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
1565 (void*)*(ref->ref.block)) );
1575 static exception_entry * inline_exception_tables(inline_node *iln,
1576 exception_entry *n_extable,
1577 exception_entry **prevextable)
1581 exception_entry *et;
1585 assert(prevextable);
1587 child = iln->children;
1590 n_extable = inline_exception_tables(child, n_extable, prevextable);
1591 child = child->next;
1592 } while (child != iln->children);
1595 et = iln->jd->exceptiontable;
1596 for (; et != NULL; et = et->down) {
1598 MZERO(n_extable, exception_entry, 1);
1599 n_extable->start = inline_map_block(iln, et->start , iln);
1600 n_extable->end = inline_map_block(iln, et->end , iln);
1601 n_extable->handler = inline_map_block(iln, et->handler, iln);
1602 n_extable->catchtype = et->catchtype;
1605 (*prevextable)->down = n_extable;
1607 *prevextable = n_extable;
1612 if (iln->handler_monitorexit) {
1613 exception_entry **activehandlers;
1615 MZERO(n_extable, exception_entry, 1);
1616 n_extable->start = iln->inlined_basicblocks;
1617 n_extable->end = iln->inlined_basicblocks_cursor;
1618 n_extable->handler = iln->handler_monitorexit;
1619 n_extable->catchtype.any = NULL; /* finally */
1622 (*prevextable)->down = n_extable;
1624 *prevextable = n_extable;
1628 /* We have to protect the created handler with the same handlers */
1629 /* that protect the method body itself. */
1631 for (scope = iln; scope->parent != NULL; scope = scope->parent) {
1633 activehandlers = scope->o_handlers;
1634 assert(activehandlers);
1636 while (*activehandlers) {
1638 assert(scope->parent);
1640 MZERO(n_extable, exception_entry, 1);
1641 n_extable->start = iln->handler_monitorexit;
1642 n_extable->end = iln->handler_monitorexit + 1; /* XXX ok in this case? */
1643 n_extable->handler = inline_map_block(scope->parent,
1644 (*activehandlers)->handler,
1646 n_extable->catchtype = (*activehandlers)->catchtype;
1649 (*prevextable)->down = n_extable;
1651 *prevextable = n_extable;
1663 static void inline_locals(inline_node *iln)
1669 iln->varmap = create_variable_map(iln);
1671 child = iln->children;
1674 inline_locals(child);
1675 child = child->next;
1676 } while (child != iln->children);
1679 if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
1680 iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
1681 if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
1682 iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
1683 if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
1684 iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
1688 static void inline_interface_variables(inline_node *iln)
1695 resultjd = iln->ctx->resultjd;
1697 resultjd->interface_map = DMNEW(interface_info, 5*iln->ctx->maxinoutdepth);
1698 for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
1699 resultjd->interface_map[i].flags = UNUSED;
1701 for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
1702 assert(bptr->indepth <= iln->ctx->maxinoutdepth);
1703 assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
1705 for (i=0; i<bptr->indepth; ++i) {
1706 v = &(resultjd->var[bptr->invars[i]]);
1708 if (v->type == TYPE_RET)
1709 v->flags |= PREALLOC;
1711 v->flags &= ~PREALLOC;
1712 v->flags &= ~INMEMORY;
1713 assert(bptr->invars[i] >= resultjd->localcount);
1715 if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1716 resultjd->interface_map[5*i + v->type].flags = v->flags;
1719 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1723 for (i=0; i<bptr->outdepth; ++i) {
1724 v = &(resultjd->var[bptr->outvars[i]]);
1726 if (v->type == TYPE_RET)
1727 v->flags |= PREALLOC;
1729 v->flags &= ~PREALLOC;
1730 v->flags &= ~INMEMORY;
1731 assert(bptr->outvars[i] >= resultjd->localcount);
1733 if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1734 resultjd->interface_map[5*i + v->type].flags = v->flags;
1737 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1744 static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
1749 builtintable_entry *bte;
1754 child = iln->children;
1757 inline_write_exception_handlers(master, child);
1758 child = child->next;
1759 } while (child != iln->children);
1762 if (iln->synchronize) {
1763 /* create the monitorexit handler */
1764 n_bptr = create_block(master, iln, iln,
1765 iln->n_passthroughcount + 1);
1766 n_bptr->type = BBTYPE_EXH;
1767 n_bptr->flags = BBFINISHED;
1769 exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1770 n_bptr->invars[iln->n_passthroughcount] = exvar;
1772 iln->handler_monitorexit = n_bptr;
1774 /* ACONST / ALOAD */
1776 n_ins = master->inlined_iinstr_cursor++;
1777 if (iln->m->flags & ACC_STATIC) {
1778 n_ins->opc = ICMD_ACONST;
1779 n_ins->sx.val.c.cls = iln->m->class;
1780 n_ins->flags.bits = INS_FLAG_CLASS;
1783 n_ins->opc = ICMD_ALOAD;
1784 n_ins->s1.varindex = iln->synclocal;
1785 assert(n_ins->s1.varindex != UNUSED);
1787 /* XXX could be PREALLOCed for builtin call */
1788 syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1789 n_ins->dst.varindex = syncvar;
1794 bte = builtintable_get_internal(LOCK_monitor_exit);
1796 n_ins = master->inlined_iinstr_cursor++;
1797 n_ins->opc = ICMD_BUILTIN;
1798 n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
1799 n_ins->sx.s23.s2.args = DMNEW(s4, n_ins->s1.argcount);
1800 n_ins->sx.s23.s2.args[0] = syncvar;
1801 for (i=0; i < iln->n_passthroughcount + 1; ++i) {
1802 n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
1804 n_ins->sx.s23.s3.bte = bte;
1809 n_ins = master->inlined_iinstr_cursor++;
1810 n_ins->opc = ICMD_ATHROW;
1811 n_ins->flags.bits = 0;
1812 n_ins->s1.varindex = exvar;
1815 /* close basic block */
1817 close_block(iln, iln, n_bptr, iln->n_passthroughcount);
1823 /* second pass driver *********************************************************/
1825 static bool test_inlining(inline_node *iln, jitdata *jd)
1830 exception_entry *n_ext;
1831 exception_entry *prevext;
1837 #if !defined(NDEBUG)
1838 static int debug_verify_inlined_code = 1; /* XXX */
1839 static int debug_compile_inlined_code_counter = 0;
1842 DOLOG( dump_inline_tree(iln, 0); );
1846 n_ins = DMNEW(instruction, iln->cumul_instructioncount);
1847 MZERO(n_ins, instruction, iln->cumul_instructioncount);
1848 iln->inlined_iinstr = n_ins;
1850 n_bb = DMNEW(basicblock, iln->cumul_basicblockcount);
1851 MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
1852 iln->inlined_basicblocks = n_bb;
1854 iln->ctx->blockmap = DMNEW(inline_block_map, iln->cumul_blockmapcount);
1856 n_jd = jit_jitdata_new(iln->m);
1857 n_jd->flags = jd->flags;
1858 n_jd->code->optlevel = jd->code->optlevel;
1859 iln->ctx->resultjd = n_jd;
1863 /* create the local_map */
1865 n_jd->local_map = DMNEW(s4, 5*iln->cumul_maxlocals);
1866 for (i=0; i<5*iln->cumul_maxlocals; ++i)
1867 n_jd->local_map[i] = UNUSED;
1869 /* create / coalesce local variables */
1877 n_jd->localcount = n_jd->vartop;
1879 /* extra variables for verification (DEBUG) */
1881 #if !defined(NDEBUG)
1882 if (debug_verify_inlined_code) {
1883 n_jd->vartop += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
1884 if (n_jd->vartop > n_jd->varcount) {
1886 n_jd->var = DMREALLOC(n_jd->var, varinfo, n_jd->varcount, n_jd->vartop);
1887 n_jd->varcount = n_jd->vartop;
1892 /* write inlined code */
1894 rewrite_method(iln);
1896 /* create exception handlers */
1898 inline_write_exception_handlers(iln, iln);
1900 /* write the dummy end block */
1902 n_bptr = create_block(iln, iln, iln, 0);
1903 n_bptr->flags = BBUNDEF;
1904 n_bptr->type = BBTYPE_STD;
1906 /* store created code in jitdata */
1908 n_jd->basicblocks = iln->inlined_basicblocks;
1909 n_jd->basicblockindex = NULL;
1910 n_jd->instructioncount = iln->cumul_instructioncount;
1911 n_jd->instructions = iln->inlined_iinstr;
1913 /* link the basic blocks (dummy end block is not counted) */
1915 n_jd->basicblockcount = (iln->inlined_basicblocks_cursor - iln->inlined_basicblocks) - 1;
1916 for (i=0; i<n_jd->basicblockcount + 1; ++i)
1917 n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
1919 n_jd->basicblocks[i-1].next = NULL;
1921 /* check basicblock numbers */
1923 #if !defined(NDEBUG)
1924 jit_check_basicblock_numbers(n_jd);
1927 /* create the exception table */
1929 if (iln->cumul_exceptiontablelength) {
1930 exception_entry *tableend;
1932 n_ext = DMNEW(exception_entry, iln->cumul_exceptiontablelength);
1934 tableend = inline_exception_tables(iln, n_ext, &prevext);
1935 assert(tableend == n_ext + iln->cumul_exceptiontablelength);
1937 prevext->down = NULL;
1939 n_jd->exceptiontablelength = iln->cumul_exceptiontablelength;
1940 n_jd->exceptiontable = n_ext;
1946 /*******************************************************************************/
1949 memcpy(n_cd, jd->cd, sizeof(codegendata));
1951 n_cd->method = NULL; /* XXX */
1952 n_jd->maxlocals = iln->cumul_maxlocals;
1953 n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
1955 inline_post_process(n_jd);
1957 inline_interface_variables(iln);
1959 #if defined(ENABLE_VERIFIER) && !defined(NDEBUG) && 0
1960 if (debug_verify_inlined_code) {
1961 debug_verify_inlined_code = 0;
1962 DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
1963 if (!typecheck(n_jd)) {
1964 *exceptionptr = NULL;
1965 DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
1969 DOLOG( printf("VERIFICATION PASSED.\n") );
1971 debug_verify_inlined_code = 1;
1973 #endif /* defined(ENABLE_VERIFIER) */
1975 /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
1977 n_jd->rd->freemem = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
1978 #if defined(HAS_4BYTE_STACKSLOT)
1979 n_jd->rd->freemem_2 = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
1982 #if !defined(NDEBUG)
1983 if (n_jd->instructioncount >= inline_debug_min_size
1984 && n_jd->instructioncount <= inline_debug_max_size)
1986 if (debug_compile_inlined_code_counter >= inline_debug_start_counter
1987 && debug_compile_inlined_code_counter <= inline_debug_end_counter)
1990 /* install the inlined result */
1992 *jd->code = *n_jd->code;
1993 n_jd->code = jd->code;
1996 #if !defined(NDEBUG)
1997 inline_count_methods++;
1999 /* inline_debug_log++; */
2001 printf("==== %d.INLINE ==================================================================\n", debug_compile_inlined_code_counter);
2002 printf("\ninline tree:\n");
2003 dump_inline_tree(iln, 0);
2004 n_jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE | JITDATA_FLAG_SHOWDISASSEMBLE;
2005 /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
2006 printf("-------- DONE -----------------------------------------------------------\n");
2009 /* inline_debug_log--; */
2013 #if !defined(NDEBUG)
2014 debug_compile_inlined_code_counter++;
2021 /* first pass: build inlining tree ********************************************/
2023 static bool inline_analyse_callee(inline_node *caller,
2025 basicblock *callerblock,
2026 instruction *calleriptr,
2028 exception_entry **handlers,
2031 inline_node *cn; /* the callee inline_node */
2037 /* create an inline tree node */
2039 cn = DNEW(inline_node);
2040 MZERO(cn, inline_node, 1);
2042 cn->ctx = caller->ctx;
2044 cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
2045 isstatic = (callee->flags & ACC_STATIC);
2047 /* get the intermediate representation of the callee */
2049 if (!inline_jit_compile(cn))
2052 /* info about the call site */
2054 cn->depth = caller->depth + 1;
2055 cn->callerblock = callerblock;
2056 cn->callerins = calleriptr;
2057 cn->callerpc = callerpc;
2058 cn->o_handlers = handlers;
2059 cn->n_handlercount = caller->n_handlercount + nhandlers;
2061 /* determine if we need basic block boundaries before/after */
2063 cn->blockbefore = false;
2064 cn->blockafter = false;
2066 if (cn->jd->branchtoentry)
2067 cn->blockbefore = true;
2069 if (cn->jd->branchtoend)
2070 cn->blockafter = true;
2072 if (cn->jd->returncount > 1)
2073 cn->blockafter = true;
2075 /* XXX make safer and reusable (maybe store last real block) */
2076 for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
2079 if (cn->jd->returnblock != bptr)
2080 cn->blockafter = true;
2082 /* info about the callee */
2084 cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
2085 cn->prolog_instructioncount = callee->parseddesc->paramcount + 2;
2086 cn->epilog_instructioncount = 1; /* INLINE_END */
2087 cn->extra_instructioncount = 0;
2089 /* we need a CHECKNULL for instance methods, except for <init> */
2091 if (!isstatic && callee->name != utf_init)
2092 cn->prolog_instructioncount += 1;
2094 /* deal with synchronized callees */
2096 if (cn->synchronize) {
2098 builtintable_entry *bte;
2100 /* we need basic block boundaries because of the handler */
2102 cn->blockbefore = true;
2103 cn->blockafter = true;
2105 /* for synchronized static methods */
2106 /* we need an ACONST, MONITORENTER in the prolog */
2107 /* and ACONST, MONITOREXIT in the epilog */
2109 /* for synchronized instance methods */
2110 /* we need an COPY, MONITORENTER in the prolog */
2111 /* and MONITOREXIT in the epilog */
2114 cn->prolog_instructioncount += 2;
2115 cn->epilog_instructioncount += 2;
2118 cn->prolog_instructioncount += 2;
2119 cn->epilog_instructioncount += 1;
2120 cn->localsoffset += 1;
2123 /* and exception handler */
2124 /* ALOAD, builtin_monitorexit, ATHROW */
2126 cn->extra_instructioncount += 3;
2128 /* exception table entries */
2130 caller->cumul_exceptiontablelength += 1 + cn->n_handlercount;
2132 /* we must call the builtins */
2134 bte = builtintable_get_internal(LOCK_monitor_enter);
2136 if (md->memuse > cn->regdata->memuse)
2137 cn->regdata->memuse = md->memuse;
2138 if (md->argintreguse > cn->regdata->argintreguse)
2139 cn->regdata->argintreguse = md->argintreguse;
2141 bte = builtintable_get_internal(LOCK_monitor_exit);
2143 if (md->memuse > cn->regdata->memuse)
2144 cn->regdata->memuse = md->memuse;
2145 if (md->argintreguse > cn->regdata->argintreguse)
2146 cn->regdata->argintreguse = md->argintreguse;
2148 caller->ctx->calls_others = true;
2151 /* determine pass-through variables */
2153 i = calleriptr->s1.argcount - callee->parseddesc->paramcount; /* max # of pass-though vars */
2155 cn->n_passthroughvars = DMNEW(s4, i);
2157 for (argi = calleriptr->s1.argcount - 1; argi >= callee->parseddesc->paramcount; --argi) {
2158 s4 idx = calleriptr->sx.s23.s2.args[argi];
2159 if (idx >= caller->jd->localcount) {
2160 cn->n_passthroughvars[j] = idx;
2164 DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
2168 cn->n_selfpassthroughcount = j;
2169 cn->n_passthroughcount = caller->n_passthroughcount + cn->n_selfpassthroughcount;
2171 /* insert the node into the inline tree */
2173 insert_inline_node(caller, cn);
2175 /* analyse recursively */
2177 if (!inline_inline_intern(callee, cn))
2180 /* subtract one block if we continue the caller block */
2182 if (!cn->blockbefore)
2183 cn->cumul_basicblockcount -= 1;
2185 /* add exception handler block for synchronized callees */
2187 if (cn->synchronize) {
2188 caller->ctx->master->cumul_basicblockcount++;
2189 caller->ctx->master->cumul_blockmapcount++;
2192 /* cumulate counters */
2194 caller->cumul_instructioncount += cn->prolog_instructioncount;
2195 caller->cumul_instructioncount += cn->epilog_instructioncount;
2196 caller->cumul_instructioncount += cn->extra_instructioncount;
2197 caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
2199 caller->cumul_basicblockcount += cn->cumul_basicblockcount;
2200 caller->cumul_blockmapcount += cn->cumul_blockmapcount;
2201 caller->cumul_exceptiontablelength += cn->cumul_exceptiontablelength;
2202 if (cn->cumul_maxlocals > caller->cumul_maxlocals)
2203 caller->cumul_maxlocals = cn->cumul_maxlocals;
2205 if (caller->cumul_basicblockcount > 10*caller->ctx->master->jd->basicblockcount) {
2207 printf("STOPPING to avoid code explosion (%d blocks)\n",
2208 caller->cumul_basicblockcount);
2213 /* XXX extra block after inlined call */
2214 if (cn->blockafter) {
2215 caller->cumul_basicblockcount += 1;
2216 caller->cumul_blockmapcount += 1;
2223 static bool inline_inline_intern(methodinfo *m, inline_node *iln)
2228 int opcode; /* invocation opcode */
2230 inline_node *active;
2231 exception_entry **handlers;
2232 exception_entry *ex;
2241 /* initialize cumulative counters */
2243 iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
2244 iln->cumul_exceptiontablelength += mjd->exceptiontablelength;
2246 /* iterate over basic blocks */
2248 for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
2250 /* ignore dummy end blocks (but count them for the blockmap) */
2252 iln->cumul_blockmapcount++;
2253 if (bptr->icount > 0 || bptr->next != NULL)
2254 iln->cumul_basicblockcount++;
2256 /* skip dead code */
2258 if (bptr->flags < BBREACHED)
2261 /* allocate the buffer of active exception handlers */
2262 /* XXX this wastes some memory, but probably it does not matter */
2264 handlers = DMNEW(exception_entry*, mjd->exceptiontablelength + 1);
2266 /* determine the active exception handlers for this block */
2267 /* XXX maybe the handlers of a block should be part of our IR */
2268 /* XXX this should share code with the type checkers */
2270 for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
2271 if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
2272 handlers[nhandlers++] = ex;
2275 handlers[nhandlers] = NULL;
2278 iptr = bptr->iinstr;
2280 iln->instructioncount += len;
2281 iln->cumul_instructioncount += len;
2283 for (; --len >= 0; ++iptr) {
2288 /****************************************/
2291 case ICMD_INVOKEVIRTUAL:
2292 case ICMD_INVOKESPECIAL:
2293 case ICMD_INVOKESTATIC:
2294 case ICMD_INVOKEINTERFACE:
2296 if (!INSTRUCTION_IS_UNRESOLVED(iptr)) {
2297 callee = iptr->sx.s23.s3.fmiref->p.method;
2301 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Code_Table") == 0
2302 && (strcmp(callee->name->text, "of") == 0
2303 || strcmp(callee->name->text, "set") == 0))
2305 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Compressor") == 0
2306 && (strcmp(callee->name->text, "output") == 0))
2308 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Decompressor") == 0
2309 && (strcmp(callee->name->text, "getcode") == 0))
2311 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Output_Buffer") == 0
2312 && (strcmp(callee->name->text, "putbyte") == 0))
2314 (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Input_Buffer") == 0
2315 && (strcmp(callee->name->text, "getbyte") == 0
2316 || strcmp(callee->name->text, "readbytes") == 0
2321 if (callee->jcodelength > 0)
2325 if (callee->flags & ACC_NATIVE)
2328 if (iln->depth >= 3)
2331 if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
2332 || opcode == ICMD_INVOKESPECIAL)) {
2333 speculative = false;
2337 /* XXX search single implementation for abstract monomorphics */
2338 if ((callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED
2340 == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED)) {
2342 static int debug_spec_inline = 94;
2343 if (debug_spec_inline-- > 0) {
2346 DOLOG( printf("SPECULATIVE INLINE: "); method_println(callee); );
2350 if (debug_spec_inline == 0) {
2351 printf("LAST INLINE: "); method_println(callee);
2352 printf(" in: "); method_println(m);
2353 printf(" master: "); method_println(iln->ctx->master->m);
2360 /* polymorphic call site */
2364 for (active = iln; active; active = active->parent) {
2365 if (callee == active->m) {
2366 DOLOG( printf("RECURSIVE!\n") );
2373 if (!inline_analyse_callee(iln, callee,
2376 iln->instructioncount - len - 1 /* XXX ugly */,
2382 method_add_assumption_monomorphic(callee, iln->ctx->master->m);
2393 /* extra ICMD_MOVE may be necessary */
2394 iln->cumul_instructioncount++;
2399 /* end of basic block */
2406 /* post processing ************************************************************/
2408 #define POSTPROCESS_SRC(varindex) live[varindex]--
2409 #define POSTPROCESS_DST(varindex) live[varindex]++
2411 #define POSTPROCESS_SRCOP(s) POSTPROCESS_SRC(iptr->s.varindex)
2412 #define POSTPROCESS_DSTOP(d) POSTPROCESS_DST(iptr->d.varindex)
2414 #define MARKSAVED(varindex) jd->var[varindex].flags |= SAVEDVAR
2416 #define MARK_ALL_SAVED \
2418 for (i=0; i<jd->vartop; ++i) \
2423 static void inline_post_process(jitdata *jd)
2429 icmdtable_entry_t *icmdt;
2432 builtintable_entry *bte;
2434 /* reset the SAVEDVAR flag of all variables */
2436 for (i=0; i<jd->vartop; ++i)
2437 jd->var[i].flags &= ~SAVEDVAR;
2439 /* allocate the life counters */
2441 live = DMNEW(s4, jd->vartop);
2442 MZERO(live, s4, jd->vartop);
2444 /* iterate over all basic blocks */
2446 for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
2447 if (bptr->flags < BBREACHED)
2450 /* make invars live */
2452 for (i=0; i<bptr->indepth; ++i)
2453 POSTPROCESS_DST(bptr->invars[i]);
2455 iptr = bptr->iinstr;
2456 iend = iptr + bptr->icount;
2458 for (; iptr < iend; ++iptr) {
2460 icmdt = &(icmd_table[iptr->opc]);
2462 switch (icmdt->dataflow) {
2464 POSTPROCESS_SRCOP(sx.s23.s3);
2466 POSTPROCESS_SRCOP(sx.s23.s2);
2468 POSTPROCESS_SRCOP(s1);
2470 if (icmdt->flags & ICMDTABLE_CALLS) {
2471 jd->isleafmethod = false;
2477 POSTPROCESS_SRCOP(sx.s23.s2);
2480 POSTPROCESS_SRCOP(s1);
2482 if (icmdt->flags & ICMDTABLE_CALLS) {
2483 jd->isleafmethod = false;
2487 POSTPROCESS_DSTOP(dst);
2491 for (i=0; i<iptr->s1.argcount; ++i) {
2492 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
2494 if (icmdt->flags & ICMDTABLE_CALLS) {
2495 jd->isleafmethod = false;
2498 POSTPROCESS_DSTOP(dst);
2502 INSTRUCTION_GET_METHODDESC(iptr, md);
2504 jd->isleafmethod = false;
2505 for (i=0; i<md->paramcount; ++i) {
2506 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
2508 for (; i<iptr->s1.argcount; ++i) {
2509 MARKSAVED(iptr->sx.s23.s2.args[i]);
2511 if (md->returntype.type != TYPE_VOID)
2512 POSTPROCESS_DSTOP(dst);
2516 bte = iptr->sx.s23.s3.bte;
2518 goto post_process_call;
2524 } /* end instruction loop */
2526 /* consume outvars */
2528 for (i=0; i<bptr->outdepth; ++i)
2529 POSTPROCESS_SRC(bptr->outvars[i]);
2531 #if !defined(NDEBUG)
2532 for (i=jd->localcount; i < jd->vartop; ++i)
2533 assert(live[i] == 0);
2536 } /* end basic block loop */
2540 /* main driver function *******************************************************/
2542 bool inline_inline(jitdata *jd)
2549 DOLOG( printf("==== INLINE ==================================================================\n");
2550 show_method(jd, SHOW_STACK); );
2552 iln = DNEW(inline_node);
2553 MZERO(iln, inline_node, 1);
2555 iln->ctx = DNEW(inline_context);
2556 MZERO(iln->ctx, inline_context, 1);
2557 iln->ctx->master = iln;
2558 iln->ctx->calls_others = false;
2561 iln->regdata = jd->rd;
2562 iln->ctx->next_debugnr = 1; /* XXX debug */
2564 iln->blockbefore = true;
2565 iln->blockafter = true;
2567 /* we cannot use m->instructioncount because it may be greater than
2568 * the actual number of instructions in the basic blocks. */
2569 iln->instructioncount = 0;
2570 iln->cumul_instructioncount = 0;
2571 iln->cumul_basicblockcount = 1 /* dummy end block */;
2573 if (inline_inline_intern(m, iln)) {
2575 DOLOG( printf("==== TEST INLINE =============================================================\n"); );
2578 test_inlining(iln, jd);
2581 DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
2588 * These are local overrides for various environment variables in Emacs.
2589 * Please do not remove this and leave it at the end of the file, where
2590 * Emacs will automagically detect them.
2591 * ---------------------------------------------------------------------
2594 * indent-tabs-mode: t
2598 * vim:noexpandtab:sw=4:ts=4: