* src/vm/jit/codegen-common.h (codegendata): Removed maxlocals. This is
[cacao.git] / src / vm / jit / inline / inline.c
1 /* src/vm/jit/inline/inline.c - method inlining
2
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
7
8    This file is part of CACAO.
9
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.
14
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.
19
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
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Edwin Steiner
28
29    Changes:
30
31    $Id: inline.c 5925 2006-11-05 23:11:27Z edwin $
32
33 */
34
35 #include "config.h"
36
37 #include "vm/types.h"
38
39 #include <assert.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <limits.h>
43
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"
54
55 #include "vm/class.h"
56 #include "vm/initialize.h"
57 #include "vm/method.h"
58 #include "vm/jit/jit.h"
59 #include "vm/jit/show.h"
60
61 #include "vm/jit/reg.h"
62 #include "vm/jit/stack.h"
63
64 #include "vm/jit/verify/typecheck.h"
65
66 #if defined(ENABLE_THREADS)
67 # include "threads/native/threads.h"
68 #endif
69
70 #if !defined(NDEBUG)
71 #define INLINE_VERBOSE
72 bool inline_debug_log = 0;
73 bool inline_debug_log_names = 0;
74 int inline_debug_start_counter = 0;
75 int inline_debug_max_size = INT_MAX;
76 int inline_debug_min_size = 0;
77 int inline_debug_end_counter = INT_MAX;
78 int inline_count_methods = 0;
79 #define DOLOG(code) do{ if (inline_debug_log) { code; } }while(0)
80 #else
81 #define DOLOG(code)
82 #endif
83
84
85 /* types **********************************************************************/
86
87 typedef struct inline_node inline_node;
88 typedef struct inline_target_ref inline_target_ref;
89 typedef struct inline_context inline_context;
90 typedef struct inline_block_map inline_block_map;
91
92 struct inline_node {
93         inline_context *ctx;
94
95         jitdata *jd;
96         methodinfo *m;
97         inline_node *children;
98         inline_node *next;                             /* next node at this depth */
99         inline_node *prev;                             /* prev node at this depth */
100         int depth;                                  /* inlining depth, 0 for root */
101
102         /* info about the call site (if depth > 0)*/
103         inline_node *parent;                /* node of the caller (NULL for root) */
104         basicblock *callerblock;         /* original block containing the INVOKE* */
105         instruction *callerins;               /* the original INVOKE* instruction */
106         s4 callerpc;
107         s4 *n_passthroughvars;
108         int n_passthroughcount;
109         int n_selfpassthroughcount;  /* # of pass-through vars of the call itself */
110         exception_entry **o_handlers;
111         int n_handlercount;                 /* # of handlers protecting this call */
112         int n_resultlocal;
113         int synclocal;                    /* variable used for synchr., or UNUSED */
114
115         bool blockbefore;                  /* block boundary before inlined body? */
116         bool blockafter;                   /* block boundary after inlined body?  */
117
118         /* info about the callee */
119         int localsoffset;
120         int prolog_instructioncount;         /* # of ICMDs in the inlining prolog */
121         int epilog_instructioncount;         /* # of ICMDs in the inlining epilog */
122         int extra_instructioncount;
123         int instructioncount;
124         bool synchronize;                /* do we have to synchronize enter/exit? */
125         basicblock *handler_monitorexit;     /* handler for synchronized inlinees */
126         s4 *varmap;
127
128         /* cumulative values */
129         int cumul_instructioncount;  /* ICMDs in this node and its children       */
130         int cumul_basicblockcount;   /* BBs started by this node and its children */
131         int cumul_blockmapcount;
132         int cumul_maxlocals;
133         int cumul_exceptiontablelength;
134
135         /* output */
136         instruction *inlined_iinstr;
137         instruction *inlined_iinstr_cursor;
138         basicblock *inlined_basicblocks;
139         basicblock *inlined_basicblocks_cursor;
140
141         /* register data */
142         registerdata *regdata;
143
144         /* temporary */
145         inline_target_ref *refs;
146         instruction *inline_start_instruction;
147
148         /* XXX debug */
149         char *indent;
150         int debugnr;
151 };
152
153 struct inline_target_ref {
154         inline_target_ref *next;
155         basicblock **ref;
156         basicblock *target;
157 };
158
159 struct inline_block_map {
160         inline_node *iln;
161         basicblock *o_block;
162         basicblock *n_block;
163 };
164
165 struct inline_context {
166         inline_node *master;
167
168         jitdata *resultjd;
169
170         int next_block_number;
171         inline_block_map *blockmap;
172         int blockmap_index;
173
174         int maxinoutdepth;
175
176         bool calls_others;
177
178         int next_debugnr; /* XXX debug */
179 };
180
181
182 /* prototypes *****************************************************************/
183
184 static bool inline_inline_intern(methodinfo *m, inline_node *iln);
185 static void inline_post_process(jitdata *jd);
186
187
188 /* debug helpers **************************************************************/
189
190 #if !defined(NDEBUG)
191 #include "inline_debug.inc"
192
193 void inline_print_stats()
194 {
195         printf("inlined callers: %d\n", inline_count_methods);
196 }
197 #endif
198
199
200 /* compilation of callees *****************************************************/
201
202 static bool inline_jit_compile_intern(jitdata *jd)
203 {
204         methodinfo *m;
205
206         /* XXX should share code with jit.c */
207
208         assert(jd);
209
210         /* XXX initialize the static function's class */
211
212         m = jd->m;
213
214         /* call the compiler passes ***********************************************/
215
216         /* call parse pass */
217
218         DOLOG( log_message_class("Parsing ", m->class) );
219         if (!parse(jd)) {
220                 return false;
221         }
222
223         /* call stack analysis pass */
224
225         if (!stack_analyse(jd)) {
226                 return false;
227         }
228
229         return true;
230 }
231
232
233 static bool inline_jit_compile(inline_node *iln)
234 {
235         bool                r;
236         methodinfo         *m;
237         jitdata            *jd;
238
239         /* XXX should share code with jit.c */
240
241         assert(iln);
242         m = iln->m;
243         assert(m);
244
245 #if defined(ENABLE_THREADS)
246         /* enter a monitor on the method */
247         lock_monitor_enter((java_objectheader *) m);
248 #endif
249
250         /* allocate jitdata structure and fill it */
251
252         jd = jit_jitdata_new(m);
253         iln->jd = jd;
254
255         jd->flags = 0; /* XXX */
256
257         /* initialize the register allocator */
258
259         reg_setup(jd);
260
261         /* setup the codegendata memory */
262
263         /* XXX do a pseudo setup */
264         jd->cd = DNEW(codegendata);
265         MZERO(jd->cd, codegendata, 1);
266         jd->cd->maxstack = m->maxstack;
267         jd->cd->method = m;
268         /* XXX uses too much dump memory codegen_setup(jd); */
269
270         /* now call internal compile function */
271
272         r = inline_jit_compile_intern(jd);
273
274         if (r) {
275                 iln->regdata = jd->rd;
276         }
277
278         /* free some memory */
279 #if 0
280
281 #if defined(ENABLE_JIT)
282 # if defined(ENABLE_INTRP)
283         if (!opt_intrp)
284 # endif
285                 codegen_free(jd);
286 #endif
287
288 #endif
289
290 #if defined(ENABLE_THREADS)
291         /* leave the monitor */
292         lock_monitor_exit((java_objectheader *) m );
293 #endif
294
295         return r;
296 }
297
298
299 /* inlining tree handling *****************************************************/
300
301 static void insert_inline_node(inline_node *parent, inline_node *child)
302 {
303         inline_node *first;
304         inline_node *succ;
305
306         assert(parent && child);
307
308         child->parent = parent;
309
310         child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
311
312         first = parent->children;
313         if (!first) {
314                 /* insert as only node */
315                 parent->children = child;
316                 child->next = child;
317                 child->prev = child;
318                 return;
319         }
320
321         /* {there is at least one child already there} */
322
323         /* XXX is this search necessary, or could we always add at the end? */
324
325         succ = first;
326         while (succ->callerpc < child->callerpc) {
327                 succ = succ->next;
328                 if (succ == first) {
329                         /* insert as last node */
330                         child->prev = first->prev;
331                         child->next = first;
332                         child->prev->next = child;
333                         child->next->prev = child;
334                         return;
335                 }
336         }
337
338         assert(succ->callerpc > child->callerpc);
339
340         /* insert before succ */
341
342         child->prev = succ->prev;
343         child->next = succ;
344         child->prev->next = child;
345         child->next->prev = child;
346 }
347
348
349 /* variable handling **********************************************************/
350
351 static s4 inline_new_variable(jitdata *jd, s4 type, s4 flags)
352 {
353         s4 index;
354         s4 newcount;
355
356         index = jd->vartop++;
357         if (index >= jd->varcount) {
358                 newcount = jd->vartop * 2; /* XXX */
359                 jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, newcount);
360                 MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
361                 jd->varcount = newcount;
362         }
363
364         jd->var[index].type = type;
365         jd->var[index].flags = flags;
366
367         return index;
368 }
369
370
371 static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
372 {
373         varinfo *v;
374         s4       newidx;
375
376         v = &(origjd->var[origidx]);
377
378         newidx = inline_new_variable(jd, v->type, v->flags);
379
380         jd->var[newidx].vv = v->vv;
381
382         return newidx;
383 }
384
385
386 static s4 inline_new_temp_variable(jitdata *jd, s4 type)
387 {
388         return inline_new_variable(jd, type, 0);
389 }
390
391
392 static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
393 {
394         s4 idx;
395
396         idx = varmap[index];
397
398         if (idx < 0) {
399                 idx = inline_new_variable_clone(jd, origjd, index);
400                 varmap[index] = idx;
401         }
402
403         return idx;
404 }
405
406
407 static s4 *create_variable_map(inline_node *callee)
408 {
409         s4 *varmap;
410         s4 i, t;
411         s4 idx;
412         s4 n_idx;
413         s4 avail;
414         varinfo *v;
415         varinfo vinfo;
416
417         /* create the variable mapping */
418
419         varmap = DMNEW(s4, callee->jd->varcount);
420         for (i=0; i<callee->jd->varcount; ++i)
421                 varmap[i] = -1;
422
423         /* translate local variables */
424
425         for (i=0; i<callee->m->maxlocals; ++i) {
426                 for (t=0; t<5; ++t) {
427                         idx = callee->jd->local_map[5*i + t];
428                         if (idx == UNUSED)
429                                 continue;
430
431                         v = &(callee->jd->var[idx]);
432                         assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
433                         v->type = t; /* XXX restore if it is TYPE_VOID */
434
435                         avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
436
437                         if (avail == UNUSED) {
438                                 avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, idx);
439                                 callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
440                         }
441
442                         varmap[idx] = avail;
443                 }
444         }
445
446         /* for synchronized instance methods we need an extra local */
447
448         if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
449                 n_idx = callee->localsoffset - 1;
450                 assert(n_idx >= 0);
451                 assert(callee->parent);
452                 assert(n_idx == callee->parent->localsoffset + callee->parent->m->maxlocals);
453
454                 avail = callee->ctx->resultjd->local_map[5*n_idx + TYPE_ADR];
455
456                 if (avail == UNUSED) {
457                         avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
458                         callee->ctx->resultjd->local_map[5*n_idx + TYPE_ADR] = avail;
459                 }
460
461                 callee->synclocal = avail;
462         }
463         else {
464                 callee->synclocal = UNUSED;
465         }
466
467         return varmap;
468 }
469
470
471 /* basic block translation ****************************************************/
472
473 #define INLINE_RETURN_REFERENCE(callee)  \
474         ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
475
476
477 static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
478 {
479         inline_target_ref *ref;
480
481         ref = DNEW(inline_target_ref);
482         ref->ref = blockp;
483         ref->next = iln->refs;
484         iln->refs = ref;
485 }
486
487
488 static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
489 {
490         inline_context *ctx;
491
492         ctx = iln->ctx;
493         assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
494
495         ctx->blockmap[ctx->blockmap_index].iln = iln;
496         ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
497         ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
498
499         ctx->blockmap_index++;
500 }
501
502
503 static basicblock * inline_map_block(inline_node *iln,
504                                                                          basicblock *o_block,
505                                                                          inline_node *targetiln)
506 {
507         inline_block_map *bm;
508         inline_block_map *bmend;
509
510         assert(iln);
511         assert(targetiln);
512
513         if (!o_block)
514                 return NULL;
515
516         bm = iln->ctx->blockmap;
517         bmend = bm + iln->ctx->blockmap_index;
518
519         while (bm < bmend) {
520                 assert(bm->iln && bm->o_block && bm->n_block);
521                 if (bm->o_block == o_block && bm->iln == targetiln)
522                         return bm->n_block;
523                 bm++;
524         }
525
526         assert(false);
527         return NULL; /* not reached */
528 }
529
530
531 static void inline_resolve_block_refs(inline_target_ref **refs,
532                                                                           basicblock *o_bptr,
533                                                                           basicblock *n_bptr)
534 {
535         inline_target_ref *ref;
536         inline_target_ref *prev;
537
538         ref = *refs;
539         prev = NULL;
540         while (ref) {
541                 if (*(ref->ref) == o_bptr) {
542
543 #if defined(INLINE_VERBOSE)
544                         if (inline_debug_log) {
545                                 if ((ptrint) o_bptr < (0x333+100)) { /* XXX */
546                                         printf("resolving RETURN block reference %p -> new L%03d (%p)\n",
547                                                         (void*)o_bptr, n_bptr->nr, (void*)n_bptr);
548                                 }
549                                 else {
550                                         printf("resolving block reference old L%03d (%p) -> new L%03d (%p)\n",
551                                                         o_bptr->nr, (void*)o_bptr, n_bptr->nr, (void*)n_bptr);
552                                 }
553                         }
554 #endif
555
556                         *(ref->ref) = n_bptr;
557                         if (prev) {
558                                 prev->next = ref->next;
559                         }
560                         else {
561                                 *refs = ref->next;
562                         }
563                 }
564                 else {
565                         prev = ref;
566                 }
567                 ref = ref->next;
568         }
569 }
570
571
572 /* basic block creation *******************************************************/
573
574 static basicblock * create_block(inline_node *container,
575                                                                  inline_node *iln,
576                                                                  inline_node *inner,
577                                                                  basicblock *o_bptr,
578                                                                  inline_target_ref **refs,
579                                                                  int indepth)
580 {
581         basicblock  *n_bptr;
582         inline_node *outer;
583         s4           i;
584         s4           depth;
585         s4           varidx;
586         s4           newvaridx;
587
588         assert(container);
589         assert(iln);
590         assert(inner);
591         assert(indepth >= 0);
592
593         n_bptr = container->inlined_basicblocks_cursor++;
594         assert(n_bptr);
595         assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
596
597         BASICBLOCK_INIT(n_bptr, iln->m);
598
599         n_bptr->iinstr = container->inlined_iinstr_cursor;
600         n_bptr->next = n_bptr + 1;
601         n_bptr->nr = container->ctx->next_block_number++;
602         n_bptr->indepth = indepth;
603         n_bptr->flags = BBFINISHED; /* XXX */
604
605         if (indepth > container->ctx->maxinoutdepth)
606                 container->ctx->maxinoutdepth = indepth;
607
608         if (indepth) {
609                 n_bptr->invars = DMNEW(s4, indepth);
610
611
612                 for (i=0; i<indepth; ++i)
613                         n_bptr->invars[i] = -1; /* XXX debug */
614
615                 /* pass-through variables enter the block */
616
617                 outer = inner->parent;
618                 while (outer != NULL) {
619                         depth = outer->n_passthroughcount;
620
621                         assert(depth + inner->n_selfpassthroughcount <= indepth);
622
623                         for (i=0; i<inner->n_selfpassthroughcount; ++i) {
624                                 varidx = inner->n_passthroughvars[i];
625                                 newvaridx =
626                                         inline_new_variable_clone(container->ctx->resultjd,
627                                                                                           outer->jd,
628                                                                                           varidx);
629                                 n_bptr->invars[depth + i] = newvaridx;
630                                 outer->varmap[varidx] = newvaridx;
631                         }
632                         inner = outer;
633                         outer = outer->parent;
634                 }
635         }
636         else {
637                 n_bptr->invars = NULL;
638         }
639
640         /* XXX move this to callers with o_bptr != NULL? */
641         if (o_bptr) {
642                 assert(refs);
643                 inline_resolve_block_refs(refs, o_bptr, n_bptr);
644         }
645
646         {
647                 varinfo *dv;
648
649                 /* XXX for the verifier. should not be here */
650
651                 dv = DMNEW(varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
652                 MZERO(dv, varinfo,  iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
653                 n_bptr->inlocals = dv;
654         }
655
656         return n_bptr;
657 }
658
659
660 static basicblock * create_body_block(inline_node *iln,
661                                                                           basicblock *o_bptr, s4 *varmap)
662 {
663         basicblock *n_bptr;
664         s4 i;
665
666         n_bptr = create_block(iln, iln, iln, o_bptr, &(iln->refs),
667                                                   o_bptr->indepth + iln->n_passthroughcount);
668
669         n_bptr->type = o_bptr->type;
670         n_bptr->flags = o_bptr->flags;
671
672         /* translate the invars of the original block */
673
674         for (i=0; i<o_bptr->indepth; ++i) {
675                 n_bptr->invars[iln->n_passthroughcount + i] =
676                         inline_translate_variable(iln->ctx->resultjd, iln->jd,
677                                 varmap,
678                                 o_bptr->invars[i]);
679         }
680
681         return n_bptr;
682 }
683
684
685 static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
686 {
687         basicblock *n_bptr;
688         s4 retcount;
689         s4 idx;
690         varinfo vinfo;
691
692         /* number of return variables */
693
694         retcount = (callee->n_resultlocal == -1
695                                 && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
696
697         /* start the epilog block */
698
699         n_bptr = create_block(caller, caller, callee, INLINE_RETURN_REFERENCE(callee),
700                         &(callee->refs), callee->n_passthroughcount + retcount);
701
702         /* return variable */
703
704         if (retcount) {
705                 idx = inline_new_variable(caller->ctx->resultjd,
706                            callee->m->parseddesc->returntype.type, 0 /* XXX */);
707                 n_bptr->invars[callee->n_passthroughcount] = idx;
708                 varmap[callee->callerins->dst.varindex] = idx;
709         }
710
711         n_bptr->flags = /* XXX original block flags */ BBFINISHED;
712         n_bptr->type = BBTYPE_STD;
713
714         return n_bptr;
715 }
716
717
718 static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
719 {
720         inline_node *outer;
721         s4           i;
722         s4           depth;
723         s4           varidx;
724
725         n_bptr->outdepth = outdepth;
726         n_bptr->outvars = DMNEW(s4, outdepth);
727
728         for (i=0; i<outdepth; ++i)
729                 n_bptr->outvars[i] = 0; /* XXX debug */
730
731         if (outdepth > iln->ctx->maxinoutdepth)
732                 iln->ctx->maxinoutdepth = outdepth;
733
734         /* pass-through variables leave the block */
735
736         outer = inner->parent;
737         while (outer != NULL) {
738                 depth = outer->n_passthroughcount;
739
740                 assert(depth + inner->n_selfpassthroughcount <= outdepth);
741
742                 for (i=0; i<inner->n_selfpassthroughcount; ++i) {
743                         varidx = inner->n_passthroughvars[i];
744                         n_bptr->outvars[depth + i] =
745                                 inline_translate_variable(iln->ctx->resultjd,
746                                                                                   outer->jd,
747                                                                                   outer->varmap,
748                                                                                   varidx);
749                 }
750                 inner = outer;
751                 outer = outer->parent;
752         }
753 }
754
755
756 static void close_prolog_block(inline_node *iln,
757                                                            basicblock *n_bptr,
758                                                            inline_node *nextcall)
759 {
760         /* XXX add original outvars! */
761         close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
762
763         /* pass-through variables */
764
765         DOLOG( printf("closed prolog block:\n");
766                    show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
767 }
768
769
770 static void close_body_block(inline_node *iln,
771                                                          basicblock *n_bptr,
772                                                          basicblock *o_bptr,
773                                                          s4 *varmap,
774                                                          s4 retcount,
775                                                          s4 retidx)
776 {
777         s4 i;
778
779         close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
780
781         /* translate the outvars of the original block */
782
783         /* XXX reuse code */
784         for (i=0; i<o_bptr->outdepth; ++i) {
785                 n_bptr->outvars[iln->n_passthroughcount + i] =
786                         inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
787                                         o_bptr->outvars[i]);
788         }
789
790         /* set the return variable, if any */
791
792         if (retcount) {
793                 assert(retidx >= 0);
794                 n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
795         }
796 }
797
798
799 /* inlined code generation ****************************************************/
800
801 static s4 emit_inlining_prolog(inline_node *iln,
802                                                            inline_node *callee,
803                                                            instruction *o_iptr,
804                                                            s4 *varmap)
805 {
806         methodinfo *calleem;
807         methoddesc *md;
808         int i;
809         int localindex;
810         int type;
811         bool isstatic;
812         instruction *n_ins;
813         insinfo_inline *insinfo;
814         s4 argvar;
815
816         assert(iln && callee && o_iptr);
817
818         calleem = callee->m;
819         md = calleem->parseddesc;
820         isstatic = (calleem->flags & ACC_STATIC);
821
822         localindex = callee->localsoffset + md->paramslots;
823
824         for (i=md->paramcount-1; i>=0; --i) {
825                 assert(iln);
826
827                 n_ins = (iln->inlined_iinstr_cursor++);
828                 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
829
830                 type = md->paramtypes[i].type;
831
832                 localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
833                 assert(callee->regdata);
834
835                 /* translate the argument variable */
836
837                 argvar = varmap[o_iptr->sx.s23.s2.args[i]];
838                 assert(argvar != UNUSED);
839
840                 /* remove preallocation from the argument variable */
841
842                 iln->ctx->resultjd->var[argvar].flags &= ~(PREALLOC | INMEMORY);
843
844                 /* check the instance slot against NULL */
845
846                 if (!isstatic && i == 0) {
847                         assert(type == TYPE_ADR);
848                         n_ins->opc = ICMD_CHECKNULL;
849                         n_ins->s1.varindex = argvar;
850                         n_ins->dst.varindex = n_ins->s1.varindex;
851                         n_ins->line = o_iptr->line;
852
853                         n_ins = (iln->inlined_iinstr_cursor++);
854                         assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
855                 }
856
857                 /* store argument into local variable of inlined callee */
858
859                 if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != UNUSED)
860                 {
861                         /* this value is used in the callee */
862
863                         if (i == 0 && callee->synclocal != UNUSED) {
864                                 /* we also need it for synchronization, so copy it */
865                                 assert(type == TYPE_ADR);
866                                 n_ins->opc = ICMD_COPY;
867                         }
868                         else {
869                                 n_ins->opc = ICMD_ISTORE + type;
870                         }
871                         n_ins->s1.varindex = argvar;
872                         n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
873                         assert(n_ins->dst.varindex != UNUSED);
874                 }
875                 else if (i == 0 && callee->synclocal != UNUSED) {
876                         /* the value is not used inside the callee, but we need it for */
877                         /* synchronization                                             */
878                         /* XXX In this case it actually makes no sense to create a     */
879                         /*     separate synchronization variable.                      */
880
881                         n_ins->opc = ICMD_NOP;
882                 }
883                 else {
884                         /* this value is not used, pop it */
885
886                         n_ins->opc = ICMD_POP;
887                         n_ins->s1.varindex = argvar;
888                 }
889                 n_ins->line = o_iptr->line;
890
891                 DOLOG( printf("%sprolog: ", iln->indent);
892                            show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
893         }
894
895         /* ASTORE for synchronized instance methods */
896
897         if (callee->synclocal != UNUSED) {
898                 n_ins = (iln->inlined_iinstr_cursor++);
899                 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
900
901                 n_ins->opc = ICMD_ASTORE;
902                 n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
903                 n_ins->dst.varindex = callee->synclocal;
904                 n_ins->line = o_iptr->line;
905
906                 assert(n_ins->s1.varindex != UNUSED);
907         }
908
909         /* INLINE_START instruction */
910
911         n_ins = (iln->inlined_iinstr_cursor++);
912         assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
913
914         insinfo = DNEW(insinfo_inline);
915         insinfo->method = callee->m;
916         insinfo->outer = iln->m;
917         insinfo->synclocal = callee->synclocal;
918         insinfo->synchronize = callee->synchronize;
919
920         n_ins->opc = ICMD_INLINE_START;
921         n_ins->sx.s23.s3.inlineinfo = insinfo;
922         n_ins->line = o_iptr->line;
923         iln->inline_start_instruction = n_ins;
924
925         DOLOG( printf("%sprolog: ", iln->indent);
926                    show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
927
928         return 0; /* XXX */
929 }
930
931
932 static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
933 {
934         instruction *n_ins;
935
936         assert(iln && callee && o_iptr);
937         assert(iln->inline_start_instruction);
938
939         /* INLINE_END instruction */
940
941         n_ins = (iln->inlined_iinstr_cursor++);
942         assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
943
944         n_ins->opc = ICMD_INLINE_END;
945         n_ins->sx.s23.s3.inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
946         n_ins->line = o_iptr->line;
947
948         DOLOG( printf("%sepilog: ", iln->indent);
949                    show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
950 }
951
952
953 #define TRANSLATE_VAROP(vo)  \
954         n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
955
956
957 static void inline_clone_instruction(inline_node *iln,
958                                                                          jitdata *jd,
959                                                                          jitdata *origjd,
960                                                                          s4 *varmap,
961                                                                          instruction *o_iptr,
962                                                                          instruction *n_iptr)
963 {
964         icmdtable_entry_t *icmdt;
965         builtintable_entry *bte;
966         methoddesc *md;
967         s4 i, j;
968         branch_target_t *table;
969         lookup_target_t *lookup;
970         inline_node *scope;
971
972         *n_iptr = *o_iptr;
973
974         icmdt = &(icmd_table[o_iptr->opc]);
975
976         switch (icmdt->dataflow) {
977                 case DF_0_TO_0:
978                         break;
979
980                 case DF_3_TO_0:
981                         TRANSLATE_VAROP(sx.s23.s3);
982                 case DF_2_TO_0:
983                         TRANSLATE_VAROP(sx.s23.s2);
984                 case DF_1_TO_0:
985                         TRANSLATE_VAROP(s1);
986                         break;
987
988                 case DF_2_TO_1:
989                         TRANSLATE_VAROP(sx.s23.s2);
990                 case DF_1_TO_1:
991                 case DF_COPY:
992                 case DF_MOVE:
993                         TRANSLATE_VAROP(s1);
994                 case DF_0_TO_1:
995                         TRANSLATE_VAROP(dst);
996                         break;
997
998                 case DF_N_TO_1:
999                         n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1000                         for (i=0; i<n_iptr->s1.argcount; ++i) {
1001                                 n_iptr->sx.s23.s2.args[i] =
1002                                         inline_translate_variable(jd, origjd, varmap,
1003                                                         o_iptr->sx.s23.s2.args[i]);
1004                         }
1005                         TRANSLATE_VAROP(dst);
1006                         break;
1007
1008                 case DF_INVOKE:
1009                         INSTRUCTION_GET_METHODDESC(n_iptr, md);
1010 clone_call:
1011                         n_iptr->s1.argcount += iln->n_passthroughcount;
1012                         n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
1013                         for (i=0; i<o_iptr->s1.argcount; ++i) {
1014                                 n_iptr->sx.s23.s2.args[i] =
1015                                         inline_translate_variable(jd, origjd, varmap,
1016                                                         o_iptr->sx.s23.s2.args[i]);
1017                         }
1018                         for (scope = iln; scope != NULL; scope = scope->parent) {
1019                                 for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
1020                                         n_iptr->sx.s23.s2.args[i++] =
1021                                                 scope->parent->varmap[scope->n_passthroughvars[j]];
1022                                 }
1023                         }
1024                         if (md->returntype.type != TYPE_VOID)
1025                                 TRANSLATE_VAROP(dst);
1026                         break;
1027
1028                 case DF_BUILTIN:
1029                         bte = n_iptr->sx.s23.s3.bte;
1030                         md = bte->md;
1031                         goto clone_call;
1032
1033                 default:
1034                         assert(0);
1035         }
1036
1037         switch (icmdt->controlflow) {
1038                 case CF_RET:
1039                         TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
1040                         /* FALLTHROUGH */
1041                 case CF_IF:
1042                 case CF_GOTO:
1043                         inline_add_block_reference(iln, &(n_iptr->dst.block));
1044                         break;
1045
1046                 case CF_JSR:
1047                         inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
1048                         break;
1049
1050                 case CF_TABLE:
1051                         i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
1052
1053                         table = DMNEW(branch_target_t, i);
1054                         MCOPY(table, o_iptr->dst.table, branch_target_t, i);
1055                         n_iptr->dst.table = table;
1056
1057                         while (--i >= 0) {
1058                                 inline_add_block_reference(iln, &(table->block));
1059                                 table++;
1060                         }
1061                         break;
1062
1063                 case CF_LOOKUP:
1064                         inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
1065
1066                         i = n_iptr->sx.s23.s2.lookupcount;
1067                         lookup = DMNEW(lookup_target_t, i);
1068                         MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
1069                         n_iptr->dst.lookup = lookup;
1070
1071                         while (--i >= 0) {
1072                                 inline_add_block_reference(iln, &(lookup->target.block));
1073                                 lookup++;
1074                         }
1075                         break;
1076         }
1077 }
1078
1079
1080 static void rewrite_method(inline_node *iln)
1081 {
1082         basicblock *o_bptr;
1083         s4 len;
1084         instruction *o_iptr;
1085         instruction *n_iptr;
1086         inline_node *nextcall;
1087         basicblock *n_bptr;
1088         inline_block_map *bm;
1089         int i;
1090         int icount;
1091         jitdata *resultjd;
1092         jitdata *origjd;
1093         char indent[100]; /* XXX debug */
1094         s4 retcount;
1095         s4 retidx;
1096
1097         assert(iln);
1098
1099         resultjd = iln->ctx->resultjd;
1100         origjd = iln->jd;
1101
1102         n_bptr = NULL;
1103         nextcall = iln->children;
1104
1105         /* XXX debug */
1106         for (i=0; i<iln->depth; ++i)
1107                 indent[i] = '\t';
1108         indent[i] = 0;
1109         iln->indent = indent;
1110
1111         DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
1112                    printf("%s(passthrough: %d+%d)\n",
1113                                 indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
1114                                 iln->n_passthroughcount); );
1115
1116         /* set memory cursors */
1117
1118         iln->inlined_iinstr_cursor = iln->inlined_iinstr;
1119         iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
1120
1121         /* loop over basic blocks */
1122
1123         o_bptr = iln->jd->basicblocks;
1124         for (; o_bptr; o_bptr = o_bptr->next) {
1125
1126                 if (o_bptr->flags < BBREACHED) {
1127
1128                         /* ignore the dummy end block */
1129
1130                         if (o_bptr->icount == 0 && o_bptr->next == NULL) {
1131                                 /* enter the following block as translation, for exception handler ranges */
1132                                 inline_block_translation(iln, o_bptr, iln->inlined_basicblocks_cursor);
1133                                 continue;
1134                         }
1135
1136                         DOLOG(
1137                         printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
1138                                         indent,
1139                                         o_bptr->nr, o_bptr->flags, o_bptr->type,
1140                                         o_bptr->indepth);
1141                         method_println(iln->m);
1142                         );
1143
1144                         n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1145
1146                         /* enter it in the blockmap */
1147
1148                         inline_block_translation(iln, o_bptr, n_bptr);
1149
1150                         close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
1151                         continue;
1152                 }
1153
1154                 len = o_bptr->icount;
1155                 o_iptr = o_bptr->iinstr;
1156
1157                 DOLOG(
1158                 printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
1159                                 indent,
1160                                 o_bptr->nr, o_bptr->flags, o_bptr->type,
1161                                 o_bptr->indepth);
1162                 method_println(iln->m);
1163                 show_basicblock(iln->jd, o_bptr, SHOW_STACK);
1164                 );
1165
1166                 if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
1167                         /* create an inlined clone of this block */
1168
1169                         n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1170                         icount = 0;
1171
1172                         /* enter it in the blockmap */
1173
1174                         inline_block_translation(iln, o_bptr, n_bptr);
1175                 }
1176                 else {
1177                         /* continue caller block */
1178
1179                         n_bptr = iln->inlined_basicblocks_cursor - 1;
1180                         icount = n_bptr->icount;
1181                 }
1182
1183                 retcount = 0;
1184                 retidx = UNUSED;
1185
1186                 while (--len >= 0) {
1187
1188                         DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false,  SHOW_STACK);
1189                                    printf("\n") );
1190
1191                         /* handle calls that will be inlined */
1192
1193                         if (nextcall && o_iptr == nextcall->callerins) {
1194
1195                                 /* write the inlining prolog */
1196
1197                                 (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
1198                                 icount += nextcall->prolog_instructioncount;
1199
1200                                 /* end current block, or glue blocks together */
1201
1202                                 n_bptr->icount = icount;
1203
1204                                 if (nextcall->blockbefore) {
1205                                         close_prolog_block(iln, n_bptr, nextcall);
1206                                 }
1207                                 else {
1208                                         /* XXX */
1209                                 }
1210
1211                                 /* check if the result is a local variable */
1212
1213                                 if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
1214                                                 && o_iptr->dst.varindex < iln->jd->localcount)
1215                                 {
1216                                         nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
1217                                 }
1218                                 else
1219                                         nextcall->n_resultlocal = -1;
1220
1221                                 /* set memory pointers in the callee */
1222
1223                                 nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
1224                                 nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
1225
1226                                 /* recurse */
1227
1228                                 DOLOG( printf("%sentering inline ", indent);
1229                                            show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1230
1231                                 rewrite_method(nextcall);
1232
1233                                 DOLOG( printf("%sleaving inline ", indent);
1234                                            show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1235
1236                                 /* update memory cursors */
1237
1238                                 assert(nextcall->inlined_iinstr_cursor
1239                                                 <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
1240                                 assert(nextcall->inlined_basicblocks_cursor
1241                                                 == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
1242                                 iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
1243                                 iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
1244
1245                                 /* start new block, or glue blocks together */
1246
1247                                 if (nextcall->blockafter) {
1248                                         n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
1249                                         icount = 0;
1250                                 }
1251                                 else {
1252                                         n_bptr = iln->inlined_basicblocks_cursor - 1;
1253                                         icount = n_bptr->icount;
1254                                         /* XXX */
1255                                 }
1256
1257                                 /* emit inlining epilog */
1258
1259                                 emit_inlining_epilog(iln, nextcall, o_iptr);
1260                                 icount++; /* XXX epilog instructions */
1261
1262                                 /* proceed to next call */
1263
1264                                 nextcall = nextcall->next;
1265                         }
1266                         else {
1267                                 n_iptr = (iln->inlined_iinstr_cursor++);
1268                                 assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1269
1270                                 switch (o_iptr->opc) {
1271                                         case ICMD_RETURN:
1272                                                 if (iln->depth == 0)
1273                                                         goto default_clone;
1274                                                 goto return_tail;
1275
1276                                         case ICMD_IRETURN:
1277                                         case ICMD_ARETURN:
1278                                         case ICMD_LRETURN:
1279                                         case ICMD_FRETURN:
1280                                         case ICMD_DRETURN:
1281                                                 if (iln->depth == 0)
1282                                                         goto default_clone;
1283                                                 retcount = 1;
1284                                                 retidx = iln->varmap[o_iptr->s1.varindex];
1285                                                 if (iln->n_resultlocal != -1) {
1286                                                         /* store result in a local variable */
1287
1288                                                         DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
1289                                                         /* This relies on the same sequence of types for */
1290                                                         /* ?STORE and ?RETURN opcodes.                   */
1291                                                         n_iptr->opc = ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN);
1292                                                         n_iptr->s1.varindex = retidx;
1293                                                         n_iptr->dst.varindex = iln->n_resultlocal;
1294
1295                                                         retcount = 0;
1296                                                         retidx = UNUSED;
1297
1298                                                         n_iptr = (iln->inlined_iinstr_cursor++);
1299                                                         assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1300                                                         icount++;
1301                                                 }
1302                                                 else if ((retidx < resultjd->localcount && iln->blockafter)
1303                                                                 || !iln->blockafter) /* XXX do we really always need the MOVE? */
1304                                                 {
1305                                                         /* local must not become outvar, insert a MOVE */
1306
1307                                                         n_iptr->opc = ICMD_MOVE;
1308                                                         n_iptr->s1.varindex = retidx;
1309                                                         retidx = inline_new_temp_variable(resultjd,
1310                                                                                                                           resultjd->var[retidx].type);
1311                                                         n_iptr->dst.varindex = retidx;
1312
1313                                                         n_iptr = (iln->inlined_iinstr_cursor++);
1314                                                         assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1315                                                         icount++;
1316                                                 }
1317 return_tail:
1318                                                 if (iln->blockafter) {
1319                                                         n_iptr->opc = ICMD_GOTO;
1320                                                         n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
1321                                                         inline_add_block_reference(iln, &(n_iptr->dst.block));
1322                                                 }
1323                                                 else {
1324                                                         n_iptr->opc = ICMD_NOP;
1325                                                 }
1326                                                 break;
1327 #if 0
1328                                                 if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
1329                                                         n_iptr->opc = ICMD_NOP;
1330                                                         break;
1331                                                 }
1332                                                 goto default_clone;
1333                                                 break;
1334 #endif
1335
1336                                         default:
1337 default_clone:
1338                                                 inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
1339                                 }
1340
1341                                 DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
1342                                            printf("\n"););
1343
1344                                 icount++;
1345                         }
1346
1347                         o_iptr++;
1348                 }
1349
1350                 /* end of basic block */
1351
1352                 if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
1353                         close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
1354                         n_bptr->icount = icount;
1355
1356                         DOLOG( printf("closed body block:\n");
1357                                    show_basicblock(resultjd, n_bptr, SHOW_STACK); );
1358                 }
1359                 else {
1360                         n_bptr->icount = icount;
1361                         assert(iln->parent);
1362                         if (retidx != UNUSED)
1363                                 iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
1364                 }
1365         }
1366
1367         bm = iln->ctx->blockmap;
1368         for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
1369                 assert(bm->iln && bm->o_block && bm->n_block);
1370                 if (bm->iln == iln)
1371                         inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block);
1372         }
1373
1374 #if !defined(NDEBUG)
1375         if (iln->refs) {
1376                 inline_target_ref *ref;
1377                 ref = iln->refs;
1378                 while (ref) {
1379                         if (!iln->depth || *(ref->ref) != INLINE_RETURN_REFERENCE(iln)) {
1380                                 DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
1381                                            (void*)*(ref->ref)) );
1382                                 assert(false);
1383                         }
1384                         ref = ref->next;
1385                 }
1386         }
1387 #endif
1388 }
1389
1390
1391 static exception_entry * inline_exception_tables(inline_node *iln,
1392                                                                                                  exception_entry *n_extable,
1393                                                                                                  exception_entry **prevextable)
1394 {
1395         inline_node *child;
1396         inline_node *scope;
1397         exception_entry *et;
1398
1399         assert(iln);
1400         assert(n_extable);
1401         assert(prevextable);
1402
1403         child = iln->children;
1404         if (child) {
1405                 do {
1406                         n_extable = inline_exception_tables(child, n_extable, prevextable);
1407                         child = child->next;
1408                 } while (child != iln->children);
1409         }
1410
1411         et = iln->jd->exceptiontable;
1412         for (; et != NULL; et = et->down) {
1413                 assert(et);
1414                 MZERO(n_extable, exception_entry, 1);
1415                 n_extable->start     = inline_map_block(iln, et->start  , iln);
1416                 n_extable->end       = inline_map_block(iln, et->end    , iln);
1417                 n_extable->handler   = inline_map_block(iln, et->handler, iln);
1418                 n_extable->catchtype = et->catchtype;
1419
1420                 if (*prevextable) {
1421                         (*prevextable)->down = n_extable;
1422                 }
1423                 *prevextable = n_extable;
1424
1425                 n_extable++;
1426         }
1427
1428         if (iln->handler_monitorexit) {
1429                 exception_entry **activehandlers;
1430
1431                 MZERO(n_extable, exception_entry, 1);
1432                 n_extable->start   = iln->inlined_basicblocks;
1433                 n_extable->end     = iln->inlined_basicblocks_cursor;
1434                 n_extable->handler = iln->handler_monitorexit;
1435                 n_extable->catchtype.any = NULL; /* finally */
1436
1437                 if (*prevextable) {
1438                         (*prevextable)->down = n_extable;
1439                 }
1440                 *prevextable = n_extable;
1441
1442                 n_extable++;
1443
1444                 /* We have to protect the created handler with the same handlers */
1445                 /* that protect the method body itself.                          */
1446
1447                 for (scope = iln; scope->parent != NULL; scope = scope->parent) {
1448
1449                         activehandlers = scope->o_handlers;
1450                         assert(activehandlers);
1451
1452                         while (*activehandlers) {
1453
1454                                 assert(scope->parent);
1455
1456                                 MZERO(n_extable, exception_entry, 1);
1457                                 n_extable->start     = iln->handler_monitorexit;
1458                                 n_extable->end       = iln->handler_monitorexit + 1; /* XXX ok in this case? */
1459                                 n_extable->handler   = inline_map_block(scope->parent,
1460                                                                                                                 (*activehandlers)->handler,
1461                                                                                                                 scope->parent);
1462                                 n_extable->catchtype = (*activehandlers)->catchtype;
1463
1464                                 if (*prevextable) {
1465                                         (*prevextable)->down = n_extable;
1466                                 }
1467                                 *prevextable = n_extable;
1468
1469                                 n_extable++;
1470                                 activehandlers++;
1471                         }
1472                 }
1473         }
1474
1475         return n_extable;
1476 }
1477
1478
1479 static void inline_locals(inline_node *iln)
1480 {
1481         inline_node *child;
1482
1483         assert(iln);
1484
1485         iln->varmap = create_variable_map(iln);
1486
1487         child = iln->children;
1488         if (child) {
1489                 do {
1490                         inline_locals(child);
1491                         child = child->next;
1492                 } while (child != iln->children);
1493         }
1494
1495         if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
1496                 iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
1497         if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
1498                 iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
1499         if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
1500                 iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
1501 }
1502
1503
1504 static void inline_interface_variables(inline_node *iln)
1505 {
1506         basicblock *bptr;
1507         jitdata *resultjd;
1508         s4 i;
1509         varinfo *v;
1510
1511         resultjd = iln->ctx->resultjd;
1512
1513         resultjd->interface_map = DMNEW(interface_info, 5*iln->ctx->maxinoutdepth);
1514         for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
1515                 resultjd->interface_map[i].flags = UNUSED;
1516
1517         for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
1518                 assert(bptr->indepth  <= iln->ctx->maxinoutdepth);
1519                 assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
1520
1521                 for (i=0; i<bptr->indepth; ++i) {
1522                         v = &(resultjd->var[bptr->invars[i]]);
1523                         v->flags |= INOUT;
1524                         v->flags &= ~PREALLOC;
1525                         v->flags &= ~INMEMORY;
1526                         assert(bptr->invars[i] >= resultjd->localcount);
1527
1528                         if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1529                                 resultjd->interface_map[5*i + v->type].flags = v->flags;
1530                         }
1531                         else {
1532                                 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1533                         }
1534                 }
1535
1536                 for (i=0; i<bptr->outdepth; ++i) {
1537                         v = &(resultjd->var[bptr->outvars[i]]);
1538                         v->flags |= INOUT;
1539                         v->flags &= ~PREALLOC;
1540                         v->flags &= ~INMEMORY;
1541                         assert(bptr->outvars[i] >= resultjd->localcount);
1542
1543                         if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
1544                                 resultjd->interface_map[5*i + v->type].flags = v->flags;
1545                         }
1546                         else {
1547                                 resultjd->interface_map[5*i + v->type].flags |= v->flags;
1548                         }
1549                 }
1550         }
1551 }
1552
1553
1554 static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
1555 {
1556         basicblock *n_bptr;
1557         instruction *n_ins;
1558         inline_node *child;
1559         builtintable_entry *bte;
1560         s4 exvar;
1561         s4 syncvar;
1562         varinfo vinfo;
1563         s4 i;
1564
1565         child = iln->children;
1566         if (child) {
1567                 do {
1568                         inline_write_exception_handlers(master, child);
1569                         child = child->next;
1570                 } while (child != iln->children);
1571         }
1572
1573         if (iln->synchronize) {
1574                 /* create the monitorexit handler */
1575                 n_bptr = create_block(master, iln, iln, NULL, NULL,
1576                                                           iln->n_passthroughcount + 1);
1577                 n_bptr->type = BBTYPE_EXH;
1578                 n_bptr->flags = BBFINISHED;
1579
1580                 exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1581                 n_bptr->invars[iln->n_passthroughcount] = exvar;
1582
1583                 iln->handler_monitorexit = n_bptr;
1584
1585                 /* ACONST / ALOAD */
1586
1587                 n_ins = master->inlined_iinstr_cursor++;
1588                 if (iln->m->flags & ACC_STATIC) {
1589                         n_ins->opc = ICMD_ACONST;
1590                         n_ins->sx.val.c.cls = iln->m->class;
1591                         n_ins->flags.bits = INS_FLAG_CLASS;
1592                 }
1593                 else {
1594                         n_ins->opc = ICMD_ALOAD;
1595                         n_ins->s1.varindex = iln->synclocal;
1596                         assert(n_ins->s1.varindex != UNUSED);
1597                 }
1598                 /* XXX could be PREALLOCed for  builtin call */
1599                 syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1600                 n_ins->dst.varindex = syncvar;
1601                 n_ins->line = 0;
1602
1603                 /* MONITOREXIT */
1604
1605                 bte = builtintable_get_internal(LOCK_monitor_exit);
1606
1607                 n_ins = master->inlined_iinstr_cursor++;
1608                 n_ins->opc = ICMD_BUILTIN;
1609                 n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
1610                 n_ins->sx.s23.s2.args = DMNEW(s4, n_ins->s1.argcount);
1611                 n_ins->sx.s23.s2.args[0] = syncvar;
1612                 for (i=0; i < iln->n_passthroughcount + 1; ++i) {
1613                         n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
1614                 }
1615                 n_ins->sx.s23.s3.bte = bte;
1616                 n_ins->line = 0;
1617
1618                 /* ATHROW */
1619
1620                 n_ins = master->inlined_iinstr_cursor++;
1621                 n_ins->opc = ICMD_ATHROW;
1622                 n_ins->flags.bits = 0;
1623                 n_ins->s1.varindex = exvar;
1624                 n_ins->line = 0;
1625
1626                 /* close basic block */
1627
1628                 close_block(iln, iln, n_bptr, iln->n_passthroughcount);
1629                 n_bptr->icount = 3;
1630         }
1631 }
1632
1633
1634 /* second pass driver *********************************************************/
1635
1636 static bool test_inlining(inline_node *iln, jitdata *jd,
1637                 jitdata **resultjd)
1638 {
1639         instruction *n_ins;
1640         basicblock *n_bb;
1641         basicblock *n_bptr;
1642         exception_entry *n_ext;
1643         exception_entry *prevext;
1644         codegendata *n_cd;
1645         jitdata *n_jd;
1646         s4 i;
1647
1648
1649         static int debug_verify_inlined_code = 1; /* XXX */
1650 #if !defined(NDEBUG)
1651         static int debug_compile_inlined_code_counter = 0;
1652 #endif
1653
1654         DOLOG( dump_inline_tree(iln, 0); );
1655
1656         assert(iln && jd && resultjd);
1657
1658         *resultjd = jd;
1659
1660         n_ins = DMNEW(instruction, iln->cumul_instructioncount);
1661         iln->inlined_iinstr = n_ins;
1662
1663         n_bb = DMNEW(basicblock, iln->cumul_basicblockcount);
1664         MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
1665         iln->inlined_basicblocks = n_bb;
1666
1667         iln->ctx->blockmap = DMNEW(inline_block_map, iln->cumul_blockmapcount);
1668
1669         n_jd = jit_jitdata_new(iln->m);
1670         n_jd->flags = jd->flags;
1671         iln->ctx->resultjd = n_jd;
1672
1673         reg_setup(n_jd);
1674
1675         /* create the local_map */
1676
1677         n_jd->local_map = DMNEW(s4, 5*iln->cumul_maxlocals);
1678         for (i=0; i<5*iln->cumul_maxlocals; ++i)
1679                 n_jd->local_map[i] = UNUSED;
1680
1681         /* create / coalesce local variables */
1682
1683         n_jd->varcount = 0;
1684         n_jd->vartop = 0;
1685         n_jd->var = NULL;
1686
1687         inline_locals(iln);
1688
1689         n_jd->localcount = n_jd->vartop;
1690
1691         /* extra variables for verification (DEBUG) */
1692
1693         if (debug_verify_inlined_code) {
1694                 n_jd->vartop   += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
1695                 if (n_jd->vartop > n_jd->varcount) {
1696                         /* XXX why? */
1697                         n_jd->var = DMREALLOC(n_jd->var, varinfo, n_jd->varcount, n_jd->vartop);
1698                         n_jd->varcount = n_jd->vartop;
1699                 }
1700         }
1701
1702         /* write inlined code */
1703
1704         rewrite_method(iln);
1705
1706         /* create exception handlers */
1707
1708         inline_write_exception_handlers(iln, iln);
1709
1710         /* write the dummy end block */
1711
1712         n_bptr = create_block(iln, iln, iln, NULL, NULL, 0);
1713         n_bptr->flags = BBUNDEF;
1714         n_bptr->type = BBTYPE_STD;
1715
1716         /* store created code in jitdata */
1717
1718         n_jd->basicblocks = iln->inlined_basicblocks;
1719         n_jd->basicblockindex = NULL;
1720         n_jd->instructioncount = iln->cumul_instructioncount;
1721         n_jd->instructions = iln->inlined_iinstr;
1722
1723         /* link the basic blocks (dummy end block is not counted) */
1724
1725         n_jd->basicblockcount = (iln->inlined_basicblocks_cursor - iln->inlined_basicblocks) - 1;
1726         for (i=0; i<n_jd->basicblockcount + 1; ++i)
1727                 n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
1728         if (i)
1729                 n_jd->basicblocks[i-1].next = NULL;
1730
1731         /* check basicblock numbers */
1732
1733 #if !defined(NDEBUG)
1734         jit_check_basicblock_numbers(n_jd);
1735 #endif
1736
1737         /* create the exception table */
1738
1739         if (iln->cumul_exceptiontablelength) {
1740                 exception_entry *tableend;
1741
1742                 n_ext = DMNEW(exception_entry, iln->cumul_exceptiontablelength);
1743                 prevext = NULL;
1744                 tableend = inline_exception_tables(iln, n_ext, &prevext);
1745                 assert(tableend == n_ext + iln->cumul_exceptiontablelength);
1746                 if (prevext)
1747                         prevext->down = NULL;
1748
1749                 n_jd->exceptiontablelength = iln->cumul_exceptiontablelength;
1750                 n_jd->exceptiontable = n_ext;
1751         }
1752         else {
1753                 n_ext = NULL;
1754         }
1755
1756         /*******************************************************************************/
1757
1758         n_cd = n_jd->cd;
1759         memcpy(n_cd, jd->cd, sizeof(codegendata));
1760
1761         n_cd->method = NULL; /* XXX */
1762         n_jd->maxlocals = iln->cumul_maxlocals;
1763         n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
1764
1765         inline_post_process(n_jd);
1766
1767         inline_interface_variables(iln);
1768
1769 #if defined(ENABLE_VERIFIER)
1770         if (debug_verify_inlined_code) {
1771                 debug_verify_inlined_code = 0;
1772                 DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
1773                 if (!typecheck(n_jd)) {
1774                         *exceptionptr = NULL;
1775                         DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
1776                         return false;
1777                 }
1778                 else {
1779                         DOLOG( printf("VERIFICATION PASSED.\n") );
1780                 }
1781                 debug_verify_inlined_code = 1;
1782         }
1783 #endif /* defined(ENABLE_VERIFIER) */
1784
1785         /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
1786
1787         n_jd->rd->freemem = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
1788 #if defined(HAS_4BYTE_STACKSLOT)
1789         n_jd->rd->freemem_2 = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
1790 #endif
1791
1792 #if !defined(NDEBUG)
1793         if (n_jd->instructioncount >= inline_debug_min_size
1794                         && n_jd->instructioncount <= inline_debug_max_size)
1795         {
1796            if (debug_compile_inlined_code_counter >= inline_debug_start_counter
1797                            && debug_compile_inlined_code_counter <= inline_debug_end_counter)
1798 #endif /* NDEBUG */
1799            {
1800                         *resultjd = n_jd;
1801
1802 #if !defined(NDEBUG)
1803                         inline_count_methods++;
1804
1805                         /* inline_debug_log++; */
1806                         DOLOG(
1807                         printf("==== %d.INLINE ==================================================================\n", debug_compile_inlined_code_counter);
1808                         printf("\ninline tree:\n");
1809                         dump_inline_tree(iln, 0);
1810                         n_jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE | JITDATA_FLAG_SHOWDISASSEMBLE;
1811                         /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
1812                         printf("-------- DONE -----------------------------------------------------------\n");
1813                         fflush(stdout);
1814                         );
1815                         /* inline_debug_log--; */
1816 #endif
1817            }
1818
1819 #if !defined(NDEBUG)
1820                 debug_compile_inlined_code_counter++;
1821         }
1822 #endif
1823         return true;
1824 }
1825
1826
1827 /* first pass: build inlining tree ********************************************/
1828
1829 static bool inline_analyse_callee(inline_node *caller,
1830                                                                   methodinfo *callee,
1831                                                                   basicblock *callerblock,
1832                                                                   instruction *calleriptr,
1833                                                                   s4 callerpc,
1834                                                                   exception_entry **handlers,
1835                                                                   s4 nhandlers)
1836 {
1837         inline_node *cn;              /* the callee inline_node */
1838         s4           argi;
1839         bool         isstatic;
1840         s4           i, j;
1841         basicblock  *bptr;
1842         instruction *iptr;
1843
1844         /* create an inline tree node */
1845
1846         cn = DNEW(inline_node);
1847         MZERO(cn, inline_node, 1);
1848
1849         cn->ctx = caller->ctx;
1850         cn->m = callee;
1851         cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
1852         isstatic = (callee->flags & ACC_STATIC);
1853
1854         /* get the intermediate representation of the callee */
1855
1856         if (!inline_jit_compile(cn))
1857                 return false;
1858
1859         /* info about the call site */
1860
1861         cn->depth = caller->depth + 1;
1862         cn->callerblock = callerblock;
1863         cn->callerins = calleriptr;
1864         cn->callerpc = callerpc;
1865         cn->o_handlers = handlers;
1866         cn->n_handlercount = caller->n_handlercount + nhandlers;
1867
1868         /* determine if we need basic block boundaries before/after */
1869
1870         cn->blockbefore = false;
1871         cn->blockafter = false;
1872
1873         if (cn->jd->branchtoentry)
1874                 cn->blockbefore = true;
1875
1876         if (cn->jd->branchtoend)
1877                 cn->blockafter = true;
1878
1879         if (cn->jd->returncount > 1)
1880                 cn->blockafter = true;
1881
1882         /* XXX make safer and reusable (maybe store last real block) */
1883         for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
1884                 ;
1885
1886         if (cn->jd->returnblock != bptr)
1887                 cn->blockafter = true;
1888
1889         /* info about the callee */
1890
1891         cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
1892         cn->prolog_instructioncount = callee->parseddesc->paramcount + 1;
1893         cn->epilog_instructioncount = 1; /* INLINE_END */
1894         cn->extra_instructioncount = 0;
1895
1896         /* we need a CHECKNULL for instance methods */
1897
1898         if (!isstatic)
1899                 cn->prolog_instructioncount += 1;
1900
1901         /* deal with synchronized callees */
1902
1903         if (cn->synchronize) {
1904                 methoddesc         *md;
1905                 builtintable_entry *bte;
1906
1907                 /* we need basic block boundaries because of the handler */
1908
1909                 cn->blockbefore = true;
1910                 cn->blockafter = true;
1911
1912                 /* for synchronized instance methods */
1913                 /* we need an ASTORE in the prolog   */
1914
1915                 if (!isstatic) {
1916                         cn->prolog_instructioncount += 1;
1917                         cn->localsoffset += 1;
1918                 }
1919
1920                 /* and exception handler */
1921                 /* ALOAD, builtin_monitorexit, ATHROW */
1922
1923                 cn->extra_instructioncount += 3;
1924
1925                 /* exception table entries */
1926
1927                 caller->cumul_exceptiontablelength += 1 + cn->n_handlercount;
1928
1929                 /* we must call the builtins */
1930
1931                 bte = builtintable_get_internal(LOCK_monitor_enter);
1932                 md = bte->md;
1933                 if (md->memuse > cn->regdata->memuse)
1934                         cn->regdata->memuse = md->memuse;
1935                 if (md->argintreguse > cn->regdata->argintreguse)
1936                         cn->regdata->argintreguse = md->argintreguse;
1937
1938                 bte = builtintable_get_internal(LOCK_monitor_exit);
1939                 md = bte->md;
1940                 if (md->memuse > cn->regdata->memuse)
1941                         cn->regdata->memuse = md->memuse;
1942                 if (md->argintreguse > cn->regdata->argintreguse)
1943                         cn->regdata->argintreguse = md->argintreguse;
1944
1945                 caller->ctx->calls_others = true;
1946         }
1947
1948         /* determine pass-through variables */
1949
1950         i = calleriptr->s1.argcount - callee->parseddesc->paramcount; /* max # of pass-though vars */
1951
1952         cn->n_passthroughvars = DMNEW(s4, i);
1953         j = 0;
1954         for (argi = calleriptr->s1.argcount - 1; argi >= callee->parseddesc->paramcount; --argi) {
1955                 s4 idx = calleriptr->sx.s23.s2.args[argi];
1956                 if (idx >= caller->jd->localcount) {
1957                         cn->n_passthroughvars[j] = idx;
1958                         j++;
1959                 }
1960                 else {
1961                         DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
1962                 }
1963         }
1964         assert(j <= i);
1965         cn->n_selfpassthroughcount = j;
1966         cn->n_passthroughcount = caller->n_passthroughcount + cn->n_selfpassthroughcount;
1967
1968         /* insert the node into the inline tree */
1969
1970         insert_inline_node(caller, cn);
1971
1972         /* analyse recursively */
1973
1974         if (!inline_inline_intern(callee, cn))
1975                 return false;
1976
1977         /* subtract one block if we continue the caller block */
1978
1979         if (!cn->blockbefore)
1980                 cn->cumul_basicblockcount -= 1;
1981
1982         /* add exception handler block for synchronized callees */
1983
1984         if (cn->synchronize) {
1985                 caller->ctx->master->cumul_basicblockcount++;
1986                 caller->ctx->master->cumul_blockmapcount++;
1987         }
1988
1989         /* cumulate counters */
1990
1991         caller->cumul_instructioncount += cn->prolog_instructioncount;
1992         caller->cumul_instructioncount += cn->epilog_instructioncount;
1993         caller->cumul_instructioncount += cn->extra_instructioncount;
1994         caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
1995
1996         caller->cumul_basicblockcount += cn->cumul_basicblockcount;
1997         caller->cumul_blockmapcount += cn->cumul_blockmapcount;
1998         caller->cumul_exceptiontablelength += cn->cumul_exceptiontablelength;
1999         if (cn->cumul_maxlocals > caller->cumul_maxlocals)
2000                 caller->cumul_maxlocals = cn->cumul_maxlocals;
2001
2002         if (caller->cumul_basicblockcount > 10*caller->ctx->master->jd->basicblockcount) {
2003 #if 0
2004                 printf("STOPPING to avoid code explosion (%d blocks)\n",
2005                                 caller->cumul_basicblockcount);
2006 #endif
2007                 return false;
2008         }
2009
2010         /* XXX extra block after inlined call */
2011         if (cn->blockafter) {
2012                 caller->cumul_basicblockcount += 1;
2013                 caller->cumul_blockmapcount += 1;
2014         }
2015
2016         return true;
2017 }
2018
2019
2020 static bool inline_inline_intern(methodinfo *m, inline_node *iln)
2021 {
2022         basicblock *bptr;
2023         s4 len;
2024         instruction *iptr;
2025         int opcode;                                   /* invocation opcode */
2026         methodinfo *callee;
2027         inline_node *active;
2028         exception_entry **handlers;
2029         exception_entry *ex;
2030         s4 nhandlers;
2031         jitdata *mjd;
2032         bool speculative;
2033
2034         assert(iln);
2035
2036         mjd = iln->jd;
2037
2038         /* initialize cumulative counters */
2039
2040         iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
2041         iln->cumul_exceptiontablelength += mjd->exceptiontablelength;
2042
2043         /* iterate over basic blocks */
2044
2045         for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
2046
2047                 /* ignore dummy end blocks (but count them for the blockmap) */
2048
2049                 iln->cumul_blockmapcount++;
2050                 if (bptr->icount > 0 || bptr->next != NULL)
2051                         iln->cumul_basicblockcount++;
2052
2053                 /* skip dead code */
2054
2055                 if (bptr->flags < BBREACHED)
2056                         continue;
2057
2058                 /* allocate the buffer of active exception handlers */
2059                 /* XXX this wastes some memory, but probably it does not matter */
2060
2061                 handlers = DMNEW(exception_entry*, mjd->exceptiontablelength + 1);
2062
2063                 /* determine the active exception handlers for this block     */
2064                 /* XXX maybe the handlers of a block should be part of our IR */
2065                 /* XXX this should share code with the type checkers          */
2066                 nhandlers = 0;
2067                 for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
2068                         if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
2069                                 handlers[nhandlers++] = ex;
2070                         }
2071                 }
2072                 handlers[nhandlers] = NULL;
2073
2074                 len = bptr->icount;
2075                 iptr = bptr->iinstr;
2076
2077                 iln->instructioncount += len;
2078                 iln->cumul_instructioncount += len;
2079
2080                 for (; --len >= 0; ++iptr) {
2081
2082                         opcode = iptr->opc;
2083
2084                         switch (opcode) {
2085                                 /****************************************/
2086                                 /* INVOKATIONS                          */
2087
2088                                 case ICMD_INVOKEVIRTUAL:
2089                                 case ICMD_INVOKESPECIAL:
2090                                 case ICMD_INVOKESTATIC:
2091                                 case ICMD_INVOKEINTERFACE:
2092
2093                                         if (!INSTRUCTION_IS_UNRESOLVED(iptr)) {
2094                                                 callee = iptr->sx.s23.s3.fmiref->p.method;
2095
2096 #if 0
2097                                                 if (
2098                                                         (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Code_Table") == 0
2099                                                                 && (strcmp(callee->name->text, "of") == 0
2100                                                                  || strcmp(callee->name->text, "set") == 0))
2101                                                         ||
2102                                                         (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Compressor") == 0
2103                                                                 && (strcmp(callee->name->text, "output") == 0))
2104                                                         ||
2105                                                         (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Decompressor") == 0
2106                                                                 && (strcmp(callee->name->text, "getcode") == 0))
2107                                                         ||
2108                                                         (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Output_Buffer") == 0
2109                                                                 && (strcmp(callee->name->text, "putbyte") == 0))
2110                                                         ||
2111                                                         (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Input_Buffer") == 0
2112                                                                 && (strcmp(callee->name->text, "getbyte") == 0
2113                                                                  || strcmp(callee->name->text, "readbytes") == 0
2114                                                                  ))
2115                                                         )
2116                                                         goto force_inline;
2117
2118                                                 if (callee->jcodelength > 0)
2119                                                         goto dont_inline;
2120 #endif
2121
2122                                                 if (callee->flags & ACC_NATIVE)
2123                                                         goto dont_inline;
2124
2125                                                 if (iln->depth >= 3)
2126                                                         goto dont_inline;
2127
2128                                                 if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
2129                                                                         || opcode == ICMD_INVOKESPECIAL)) {
2130                                                         speculative = false;
2131                                                         goto maybe_inline;
2132                                                 }
2133
2134                                                 if (callee->flags & ACC_METHOD_MONOMORPHIC) {
2135                                                         /* XXX */
2136                                                         if (0
2137                                                                 && strncmp(callee->class->name->text, "java/", 5) != 0
2138                                                                 && strncmp(callee->class->name->text, "gnu/", 4) != 0
2139                                                            )
2140                                                         {
2141                                                                 printf("SPECULATIVE INLINE: "); method_println(callee);
2142                                                                 speculative = true;
2143                                                                 goto maybe_inline;
2144                                                         }
2145                                                 }
2146
2147                                                 /* polymorphic call site */
2148                                                 goto dont_inline;
2149
2150 maybe_inline:
2151                                                 for (active = iln; active; active = active->parent) {
2152                                                         if (callee == active->m) {
2153                                                                 DOLOG( printf("RECURSIVE!\n") );
2154                                                                 goto dont_inline;
2155                                                         }
2156                                                 }
2157
2158 force_inline:
2159                                                 if (!inline_analyse_callee(iln, callee,
2160                                                                         bptr,
2161                                                                         iptr,
2162                                                                         iln->instructioncount - len - 1 /* XXX ugly */,
2163                                                                         handlers,
2164                                                                         nhandlers))
2165                                                         return false;
2166
2167                                                 if (speculative)
2168                                                         method_add_assumption_monomorphic(callee, iln->ctx->master->m);
2169                                         }
2170 dont_inline:
2171                                         break;
2172
2173                                 case ICMD_RETURN:
2174                                 case ICMD_IRETURN:
2175                                 case ICMD_ARETURN:
2176                                 case ICMD_LRETURN:
2177                                 case ICMD_FRETURN:
2178                                 case ICMD_DRETURN:
2179                                         /* extra ICMD_MOVE may be necessary */
2180                                         iln->cumul_instructioncount++;
2181                                         break;
2182                         }
2183                 }
2184
2185                 /* end of basic block */
2186         }
2187
2188         return true;
2189 }
2190
2191
2192 /* post processing ************************************************************/
2193
2194 #define POSTPROCESS_SRC(varindex)  live[varindex]--
2195 #define POSTPROCESS_DST(varindex)  live[varindex]++
2196
2197 #define POSTPROCESS_SRCOP(s)  POSTPROCESS_SRC(iptr->s.varindex)
2198 #define POSTPROCESS_DSTOP(d)  POSTPROCESS_DST(iptr->d.varindex)
2199
2200 #define MARKSAVED(varindex)  jd->var[varindex].flags |= SAVEDVAR
2201
2202 #define MARK_ALL_SAVED                                               \
2203     do {                                                             \
2204         for (i=0; i<jd->vartop; ++i)                                 \
2205             if (live[i])                                             \
2206                 MARKSAVED(i);                                        \
2207     } while (0)
2208
2209 static void inline_post_process(jitdata *jd)
2210 {
2211         basicblock *bptr;
2212         instruction *iptr;
2213         instruction *iend;
2214         s4 i;
2215         icmdtable_entry_t *icmdt;
2216         s4 *live;
2217         methoddesc *md;
2218         builtintable_entry *bte;
2219
2220         /* reset the SAVEDVAR flag of all variables */
2221
2222         for (i=0; i<jd->vartop; ++i)
2223                 jd->var[i].flags &= ~SAVEDVAR;
2224
2225         /* allocate the life counters */
2226
2227         live = DMNEW(s4, jd->vartop);
2228         MZERO(live, s4, jd->vartop);
2229
2230         /* iterate over all basic blocks */
2231
2232         for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
2233                 if (bptr->flags < BBREACHED)
2234                         continue;
2235
2236                 /* make invars live */
2237
2238                 for (i=0; i<bptr->indepth; ++i)
2239                         POSTPROCESS_DST(bptr->invars[i]);
2240
2241                 iptr = bptr->iinstr;
2242                 iend = iptr + bptr->icount;
2243
2244                 for (; iptr < iend; ++iptr) {
2245
2246                         icmdt = &(icmd_table[iptr->opc]);
2247
2248                         switch (icmdt->dataflow) {
2249                                 case DF_3_TO_0:
2250                                         POSTPROCESS_SRCOP(sx.s23.s3);
2251                                 case DF_2_TO_0:
2252                                         POSTPROCESS_SRCOP(sx.s23.s2);
2253                                 case DF_1_TO_0:
2254                                         POSTPROCESS_SRCOP(s1);
2255                                 case DF_0_TO_0:
2256                                         if (icmdt->flags & ICMDTABLE_CALLS) {
2257                                                 jd->isleafmethod = false;
2258                                                 MARK_ALL_SAVED;
2259                                         }
2260                                         break;
2261
2262                                 case DF_2_TO_1:
2263                                         POSTPROCESS_SRCOP(sx.s23.s2);
2264                                 case DF_1_TO_1:
2265                                 case DF_MOVE:
2266                                         POSTPROCESS_SRCOP(s1);
2267                                 case DF_0_TO_1:
2268                                         if (icmdt->flags & ICMDTABLE_CALLS) {
2269                                                 jd->isleafmethod = false;
2270                                                 MARK_ALL_SAVED;
2271                                         }
2272                                 case DF_COPY:
2273                                         POSTPROCESS_DSTOP(dst);
2274                                         break;
2275
2276                                 case DF_N_TO_1:
2277                                         for (i=0; i<iptr->s1.argcount; ++i) {
2278                                                 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
2279                                         }
2280                                         if (icmdt->flags & ICMDTABLE_CALLS) {
2281                                                 jd->isleafmethod = false;
2282                                                 MARK_ALL_SAVED;
2283                                         }
2284                                         POSTPROCESS_DSTOP(dst);
2285                                         break;
2286
2287                                 case DF_INVOKE:
2288                                         INSTRUCTION_GET_METHODDESC(iptr, md);
2289                 post_process_call:
2290                                         jd->isleafmethod = false;
2291                                         for (i=0; i<md->paramcount; ++i) {
2292                                                 POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
2293                                         }
2294                                         for (; i<iptr->s1.argcount; ++i) {
2295                                                 MARKSAVED(iptr->sx.s23.s2.args[i]);
2296                                         }
2297                                         if (md->returntype.type != TYPE_VOID)
2298                                                 POSTPROCESS_DSTOP(dst);
2299                                         break;
2300
2301                                 case DF_BUILTIN:
2302                                         bte = iptr->sx.s23.s3.bte;
2303                                         md = bte->md;
2304                                         goto post_process_call;
2305
2306                                 default:
2307                                         assert(0);
2308                         }
2309
2310                 } /* end instruction loop */
2311
2312                 /* consume outvars */
2313
2314                 for (i=0; i<bptr->outdepth; ++i)
2315                         POSTPROCESS_SRC(bptr->outvars[i]);
2316
2317 #if !defined(NDEBUG)
2318                 for (i=jd->localcount; i < jd->vartop; ++i)
2319                         assert(live[i] == 0);
2320 #endif
2321
2322         } /* end basic block loop */
2323 }
2324
2325
2326 /* main driver function *******************************************************/
2327
2328 bool inline_inline(jitdata *jd, jitdata **resultjd)
2329 {
2330         inline_node *iln;
2331         methodinfo *m;
2332
2333         m = jd->m;
2334
2335         *resultjd = jd;
2336
2337         DOLOG( printf("==== INLINE ==================================================================\n");
2338                    show_method(jd, SHOW_STACK); );
2339
2340         iln = DNEW(inline_node);
2341         MZERO(iln, inline_node, 1);
2342
2343         iln->ctx = DNEW(inline_context);
2344         MZERO(iln->ctx, inline_context, 1);
2345         iln->ctx->master = iln;
2346         iln->ctx->calls_others = false;
2347         iln->m = m;
2348         iln->jd = jd;
2349         iln->regdata = jd->rd;
2350         iln->ctx->next_debugnr = 1; /* XXX debug */
2351
2352         iln->blockbefore = true;
2353         iln->blockafter = true;
2354
2355         /* we cannot use m->instructioncount because it may be greater than
2356          * the actual number of instructions in the basic blocks. */
2357         iln->instructioncount = 0;
2358         iln->cumul_instructioncount = 0;
2359         iln->cumul_basicblockcount = 1 /* dummy end block */;
2360
2361         if (inline_inline_intern(m, iln)) {
2362
2363                 DOLOG( printf("==== TEST INLINE =============================================================\n"); );
2364
2365                 if (iln->children)
2366                         test_inlining(iln, jd, resultjd);
2367         }
2368
2369         DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
2370         fflush(stdout); );
2371
2372         return true;
2373 }
2374
2375 /*
2376  * These are local overrides for various environment variables in Emacs.
2377  * Please do not remove this and leave it at the end of the file, where
2378  * Emacs will automagically detect them.
2379  * ---------------------------------------------------------------------
2380  * Local variables:
2381  * mode: c
2382  * indent-tabs-mode: t
2383  * c-basic-offset: 4
2384  * tab-width: 4
2385  * End:
2386  * vim:noexpandtab:sw=4:ts=4:
2387  */