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