* src/vm/jit/inline/inline.c (create_block): Use BASICBLOCK_INIT.
[cacao.git] / src / vm / jit / inline / inline.c
1 /* src/vm/jit/inline/inline.c - code inliner
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 4736 2006-04-05 11:32:52Z 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/global.h"
47 #include "vm/options.h"
48 #include "vm/statistics.h"
49 #include "vm/jit/jit.h"
50 #include "vm/jit/parse.h"
51 #include "vm/jit/inline/inline.h"
52 #include "vm/jit/loop/loop.h"
53
54 #include "vm/class.h"
55 #include "vm/initialize.h"
56 #include "vm/method.h"
57 #include "vm/jit/jit.h"
58
59 #include "vm/jit/reg.h"
60 #include "vm/jit/stack.h"
61
62 #include "vm/jit/verify/typecheck.h"
63
64 #if defined(USE_THREADS)
65 # if defined(NATIVE_THREADS)
66 #  include "threads/native/threads.h"
67 # else
68 #  include "threads/green/threads.h"
69 # endif
70 #endif
71
72 #ifndef NDEBUG
73 bool inline_debug_log = 0;
74 bool inline_debug_log_names = 0;
75 int inline_debug_start_counter = 0;
76 int inline_debug_max_size = INT_MAX;
77 int inline_debug_min_size = 0;
78 int inline_debug_end_counter = INT_MAX;
79 int inline_count_methods = 0;
80 #define DOLOG(code) do{ if (inline_debug_log) { code; } }while(0)
81 #else
82 #define DOLOG(code)
83 #endif
84
85 typedef struct inline_node inline_node;
86 typedef struct inline_target_ref inline_target_ref;
87 typedef struct inline_context inline_context;
88 typedef struct inline_stack_translation inline_stack_translation;
89 typedef struct inline_block_map inline_block_map;
90
91 struct inline_node {
92         inline_context *ctx;
93         
94         methodinfo *m;
95         inline_node *children;
96         inline_node *next;
97         inline_node *prev;
98         int depth;
99         
100         /* info about the call site (if depth > 0)*/
101         inline_node *parent;
102         basicblock *callerblock;
103         instruction *callerins;
104         s4 callerpc;
105         stackptr n_callerstack;
106         int n_callerstackdepth;
107         stackptr o_callerstack;
108         exceptiontable **o_handlers;
109
110         /* info about the callee */
111         int localsoffset;
112         int prolog_instructioncount;
113         int epilog_instructioncount;
114         int extra_instructioncount;
115         int instructioncount;
116         int stackcount;
117         bool synchronize;
118         basicblock *handler_monitorexit;
119         
120         /* cumulative values */
121         int cumul_instructioncount;
122         int cumul_stackcount;
123         int cumul_basicblockcount;
124         int cumul_maxstack;
125         int cumul_maxlocals;
126         int cumul_exceptiontablelength;
127
128         /* output */
129         instruction *inlined_iinstr;
130         instruction *inlined_iinstr_cursor;
131         stackptr n_inlined_stack;
132         stackptr n_inlined_stack_cursor;
133         basicblock *inlined_basicblocks;
134         basicblock *inlined_basicblocks_cursor;
135
136         /* register data */
137         registerdata *regdata;
138
139         /* temporary */
140         inline_target_ref *refs;
141         instruction *inline_start_instruction;
142 };
143
144 struct inline_target_ref {
145         inline_target_ref *next;
146         basicblock **ref;
147         basicblock *target;
148 };
149
150 struct inline_stack_translation {
151         stackptr o_sp;
152         stackptr n_sp;
153 };
154
155 struct inline_block_map {
156         inline_node *iln;
157         basicblock *o_block;
158         basicblock *n_block;
159 };
160
161 struct inline_context {
162         inline_node *master;
163
164         int next_block_number;
165         inline_block_map *blockmap;
166         int blockmap_index;
167
168         bool calls_others;
169         
170         stackptr o_translationlimit; /* if a stackptr is smaller than this, look it up in the table */
171         stackptr n_debug_stackbase;
172         inline_stack_translation *stacktranslationstart;
173
174         inline_stack_translation stacktranslation[1]; /* XXX VARIABLE LENGTH! */
175 };
176
177 static int stack_depth(stackptr sp)
178 {
179         int depth = 0;
180         while (sp) {
181                 depth++;
182                 sp = sp->prev;
183         }
184         return depth;
185 }
186
187 #ifndef NDEBUG
188 #include "inline_debug.c"
189
190 void inline_print_stats()
191 {
192         printf("inlined callers: %d\n",inline_count_methods);
193 }
194 #endif
195
196 static bool inline_jit_compile_intern(jitdata *jd)
197 {
198         methodinfo *m;
199         
200         assert(jd);
201         
202         /* XXX initialize the static function's class */
203
204         m = jd->m;
205         m->isleafmethod = true;
206
207         /* call the compiler passes ***********************************************/
208
209         /* call parse pass */
210
211         DOLOG( log_message_class("Parsing ", m->class) );
212         if (!parse(jd)) {
213                 return false;
214         }
215
216         /* call stack analysis pass */
217
218         if (!stack_analyse(jd)) {
219                 return false;
220         }
221
222         return true;
223 }
224
225 static bool inline_jit_compile(inline_node *iln)
226 {
227         bool                r;
228         methodinfo         *m;
229         jitdata            *jd;
230         s4 i;
231
232         assert(iln);
233         m = iln->m;
234         assert(m);
235
236 #if defined(USE_THREADS)
237         /* enter a monitor on the method */
238         builtin_monitorenter((java_objectheader *) m);
239 #endif
240         
241         /* XXX dont parse these a second time because parse is not idempotent */
242         for (i=0; i<m->jcodelength; ++i) {
243                 if (m->jcode[i] == JAVA_TABLESWITCH || m->jcode[i] == JAVA_LOOKUPSWITCH) {
244                         r = false;
245                         goto return_r;
246                 }
247         }
248
249         /* allocate jitdata structure and fill it */
250
251         jd = DNEW(jitdata);
252
253         jd->m     = m;
254         jd->cd    = DNEW(codegendata);
255         jd->rd    = DNEW(registerdata);
256 #if defined(ENABLE_LOOP)
257         jd->ld    = DNEW(loopdata);
258 #endif
259         jd->flags = 0;
260
261         /* Allocate codeinfo memory from the heap as we need to keep them. */
262
263         jd->code  = code_codeinfo_new(m); /* XXX check allocation */
264
265 #if defined(ENABLE_JIT)
266 # if defined(ENABLE_INTRP)
267         if (!opt_intrp)
268 # endif
269                 /* initialize the register allocator */
270                 reg_setup(jd);
271 #endif
272
273         /* setup the codegendata memory */
274
275         codegen_setup(jd);
276
277         /* now call internal compile function */
278
279         r = inline_jit_compile_intern(jd);
280
281         if (r) {
282                 iln->regdata = jd->rd;
283         }
284
285         /* free some memory */
286 #if 0
287
288         
289 #if defined(ENABLE_JIT)
290 # if defined(ENABLE_INTRP)
291         if (!opt_intrp)
292 # endif
293                 codegen_free(jd);
294 #endif
295
296 #endif
297
298 return_r:
299 #if defined(USE_THREADS)
300         /* leave the monitor */
301         builtin_monitorexit((java_objectheader *) m );
302 #endif
303
304 #if 0
305         stack_show_method(jd);
306 #endif
307
308         return r;
309 }
310
311 static void insert_inline_node(inline_node *parent,inline_node *child)
312 {
313         inline_node *first;
314         inline_node *succ;
315
316         assert(parent && child);
317
318         child->parent = parent;
319
320         first = parent->children;
321         if (!first) {
322                 /* insert as only node */
323                 parent->children = child;
324                 child->next = child;
325                 child->prev = child;
326                 return;
327         }
328
329         /* {there is at least one child already there} */
330
331         succ = first;
332         while (succ->callerpc < child->callerpc) {
333                 succ = succ->next;
334                 if (succ == first) {
335                         /* insert as last node */
336                         child->prev = first->prev;
337                         child->next = first;
338                         child->prev->next = child;
339                         child->next->prev = child;
340                         return;
341                 }
342         }
343
344         assert(succ->callerpc > child->callerpc);
345         
346         /* insert before succ */
347
348         child->prev = succ->prev;
349         child->next = succ;
350         child->prev->next = child;
351         child->next->prev = child;
352 }
353
354 static stackptr relocate_stack_ptr_intern(inline_node *iln,stackptr o_link,ptrint curreloc)
355 {
356         inline_stack_translation *tr;
357         
358         if (o_link) {
359                 /* XXX should limit range in both directions */
360                 if (o_link < iln->ctx->o_translationlimit) {
361                         /* this stack slot is from an earlier chunk, we must look it up */
362                         tr = iln->ctx->stacktranslationstart;
363                         while (tr >= iln->ctx->stacktranslation) {
364                                 if (o_link == tr->o_sp) {
365                                         DOLOG(printf("\t\t\ttable lookup %p -> %d\n",(void*)o_link,DEBUG_SLOT(tr->n_sp)));
366                                         return tr->n_sp;
367                                 }
368                                 tr--;
369                         }
370                         DOLOG(debug_dump_inline_context(iln));
371                         DOLOG(printf("\t\tFAILED TO TRANSLATE: %p\n",(void*)o_link));
372                         assert(false);
373                 }
374                 else {
375                         /* this stack slot it in the most recent chunk */
376                         assert(curreloc);
377                         DOLOG( printf("\t\t\toffset %d\n",(int)curreloc) );
378                         return (stackptr) ((u1*)o_link + curreloc);
379                 }
380         }
381         return iln->n_callerstack;
382 }
383
384 /* XXX for debugging */
385 static stackptr relocate_stack_ptr(inline_node *iln,stackptr o_link,ptrint curreloc)
386 {
387         stackptr new;
388
389         new = relocate_stack_ptr_intern(iln,o_link,curreloc);
390         DOLOG(
391                 printf("\t\treloc %p -> %d (%p)\t(translimit=%p)\n",
392                                 (void*)o_link,DEBUG_SLOT(new),(void*)new,(void*)iln->ctx->o_translationlimit)
393         );
394         return new;
395 }
396
397 static void emit_instruction(inline_node *iln,instruction *ins,ptrint curreloc,stackptr o_curstack)
398 {
399         char indent[100];
400         int i;
401         instruction *n_ins;
402         inline_target_ref *ref;
403
404         assert(iln && ins);
405
406         for (i=0; i<iln->depth; ++i)
407                 indent[i] = '\t';
408         indent[i] = 0;
409
410         n_ins = (iln->inlined_iinstr_cursor++);
411         assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
412         
413         *n_ins = *ins;
414
415         switch (n_ins[0].opc) {
416                                 /****************************************/
417                                 /* VARIABLE ACCESS                      */
418
419                         case ICMD_ILOAD:
420                         case ICMD_IINC:
421                         case ICMD_FLOAD:
422                         case ICMD_LLOAD:
423                         case ICMD_DLOAD:
424                         case ICMD_ISTORE:
425                         case ICMD_FSTORE:
426                         case ICMD_LSTORE:
427                         case ICMD_DSTORE:
428                         case ICMD_ALOAD:
429                         case ICMD_ASTORE:
430                     case ICMD_RET:
431                         n_ins[0].op1 += iln->localsoffset;
432                         break;
433
434                         case ICMD_GOTO:
435                         case ICMD_IFNULL:
436                         case ICMD_IFNONNULL:
437                         case ICMD_IFEQ:
438                         case ICMD_IFNE:
439                         case ICMD_IFLT:
440                         case ICMD_IFGE:
441                         case ICMD_IFGT:
442                         case ICMD_IFLE:
443                         case ICMD_IF_ICMPEQ:
444                         case ICMD_IF_ICMPNE:
445                         case ICMD_IF_ICMPLT:
446                         case ICMD_IF_ICMPGE:
447                         case ICMD_IF_ICMPGT:
448                         case ICMD_IF_ICMPLE:
449                         case ICMD_IF_ACMPEQ:
450                         case ICMD_IF_ACMPNE:
451                         case ICMD_IF_LEQ:
452                         case ICMD_IF_LNE:
453                         case ICMD_IF_LLT:
454                         case ICMD_IF_LGE:
455                         case ICMD_IF_LGT:
456                         case ICMD_IF_LLE:
457                         case ICMD_IF_LCMPEQ:
458                         case ICMD_IF_LCMPNE:
459                         case ICMD_IF_LCMPLT:
460                         case ICMD_IF_LCMPGE:
461                         case ICMD_IF_LCMPGT:
462                         case ICMD_IF_LCMPLE:
463                         case ICMD_JSR:
464                                 ref = DNEW(inline_target_ref);
465                                 ref->ref = (basicblock **) &(n_ins[0].target);
466                                 ref->next = iln->refs;
467                                 iln->refs = ref;
468                                 break;
469
470                                 /****************************************/
471                                 /* RETURNS                              */
472
473                         case ICMD_RETURN:
474                                 if (iln->parent) {
475                                         n_ins[0].opc = ICMD_GOTO;
476                                         n_ins[0].dst = NULL;
477                                         goto return_tail;
478                                 }
479                                 break;
480
481                         case ICMD_ARETURN:
482                         case ICMD_IRETURN:
483                         case ICMD_LRETURN:
484                         case ICMD_FRETURN:
485                         case ICMD_DRETURN:
486                         if (iln->parent) {
487                                 n_ins[0].opc = ICMD_INLINE_GOTO;
488                                 n_ins[0].dst = o_curstack;
489 return_tail:
490                                 n_ins[0].target = (void *) (ptrint) (iln->depth + 0x333); /* XXX */
491                                 ref = DNEW(inline_target_ref);
492                                 ref->ref = (basicblock **) &(n_ins[0].target);
493                                 ref->next = iln->refs;
494                                 iln->refs = ref;
495                         }
496                         break;
497         }
498
499         n_ins[0].dst = relocate_stack_ptr(iln,n_ins[0].dst,curreloc);
500 }
501
502 static stackptr inline_new_stackslot(inline_node *iln,stackptr n_curstack,s4 type)
503 {
504         stackptr n_sp;
505
506         n_sp = iln->n_inlined_stack_cursor++;
507         assert((n_sp - iln->n_inlined_stack) < iln->cumul_stackcount);
508
509         n_sp->prev = n_curstack;
510         n_sp->type = type;
511         n_sp->varkind = TEMPVAR;
512         n_sp->varnum = stack_depth(n_curstack); /* XXX inefficient */
513         n_sp->flags = 0;
514 #ifndef NDEBUG
515         n_sp->regoff = (IS_FLT_DBL_TYPE(type)) ? -1 : INT_ARG_CNT;
516 #endif
517
518         return n_sp;
519 }
520
521 static stackptr emit_inlining_prolog(inline_node *iln,inline_node *callee,stackptr n_curstack,instruction *o_iptr)
522 {
523         methodinfo *calleem;
524         methoddesc *md;
525         int i;
526         int localindex;
527         int depth;
528         int type;
529         bool isstatic;
530         instruction *n_ins;
531         insinfo_inline *insinfo;
532
533         assert(iln && callee && o_iptr);
534
535         calleem = callee->m;
536         md = calleem->parseddesc;
537         isstatic = (calleem->flags & ACC_STATIC);
538
539         localindex = callee->localsoffset + md->paramslots;
540         depth = stack_depth(n_curstack) - 1; /* XXX inefficient */
541         for (i=md->paramcount-1; i>=0; --i) {
542                 assert(iln);
543
544                 n_ins = (iln->inlined_iinstr_cursor++);
545                 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
546
547                 type = md->paramtypes[i].type;
548
549                 localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
550                 assert(callee->regdata);
551
552                 DOLOG( printf("prologlocal %d type=%d lofs=%d in ",
553                            localindex - callee->localsoffset,
554                            callee->regdata->locals[localindex - callee->localsoffset][type].type,callee->localsoffset);
555                                 method_println(callee->m); );
556
557                 if ((callee->regdata->locals[localindex - callee->localsoffset][type].type >= 0)
558                                 ||
559                         (i==0 && callee->synchronize && !isstatic)) 
560                 {
561                         n_ins->opc = ICMD_ISTORE + type;
562                         n_ins->op1 = localindex;
563                 }
564                 else {
565                         n_ins->opc = IS_2_WORD_TYPE(type) ? ICMD_POP2 : ICMD_POP; /* XXX is POP2 correct? */
566                 }
567                 n_ins->line = o_iptr->line;
568                 assert(n_curstack);
569                 if (n_curstack->varkind == ARGVAR) {
570                         n_curstack->varkind = TEMPVAR;
571                         n_curstack->varnum = depth;
572                         n_curstack->flags &= ~INMEMORY;
573                 }
574                 n_curstack = n_curstack->prev;
575                 n_ins->dst = n_curstack;
576                 depth--;
577         }
578
579         /* INLINE_START instruction */
580
581         n_ins = (iln->inlined_iinstr_cursor++);
582         assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
583
584         insinfo = DNEW(insinfo_inline);
585         insinfo->method = callee->m;
586         insinfo->outer = iln->m;
587         /* XXX using local 0 only works if it is read-only!! */
588         insinfo->synclocal = callee->localsoffset;
589         insinfo->synchronize = callee->synchronize;
590
591         n_ins->opc = ICMD_INLINE_START;
592         n_ins->dst = n_curstack;
593         n_ins->target = insinfo;
594         n_ins->line = o_iptr->line;
595         iln->inline_start_instruction = n_ins;
596
597         return n_curstack;
598 }
599
600 static void emit_inlining_epilog(inline_node *iln,inline_node *callee,stackptr n_curstack,instruction *o_iptr)
601 {
602         instruction *n_ins;
603         
604         assert(iln && callee && o_iptr);
605         assert(iln->inline_start_instruction);
606
607         n_ins = (iln->inlined_iinstr_cursor++);
608         assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
609
610         n_ins->opc = ICMD_INLINE_END;
611         n_ins->dst = n_curstack;
612         n_ins->target = iln->inline_start_instruction->target; /* insinfo_inline * */
613         n_ins->line = o_iptr->line;
614 }
615
616 static void rewrite_stack(inline_node *iln,stackptr o_first,stackptr o_last,ptrint curreloc)
617 {
618         int n;
619         stackptr o_sp;
620         stackptr n_sp;
621         
622         assert(iln);
623
624         if (!o_first) {
625                 assert(!o_last);
626                 DOLOG(printf("rewrite_stack: no stack slots\n"));
627                 return;
628         }
629
630         assert(o_first);
631         assert(o_last);
632         assert(o_first <= o_last);
633
634         n = o_last - o_first + 1;
635         assert(n >= 0);
636
637         o_sp = o_first;
638         n_sp = iln->n_inlined_stack_cursor;
639         
640         DOLOG(
641         printf("rewrite_stack: rewriting %d stack slots (%p,%p) -> (%d,%d)\n",
642                         n,(void*)o_first,(void*)o_last,DEBUG_SLOT(n_sp),
643                         DEBUG_SLOT(n_sp+n-1))
644         );
645
646         DOLOG( printf("o_first = "); debug_dump_stack(o_first); printf("\n") );
647         DOLOG( printf("o_last = "); debug_dump_stack(o_last); printf("\n") );
648         
649         while (o_sp <= o_last) {
650                 *n_sp = *o_sp;
651
652                 n_sp->prev = relocate_stack_ptr(iln,n_sp->prev,curreloc);
653                 switch (n_sp->varkind) {
654                         case STACKVAR: n_sp->varnum += iln->n_callerstackdepth; break;
655                         case LOCALVAR: n_sp->varnum += iln->localsoffset; break;
656                 }
657                 
658                 o_sp++;
659                 n_sp++;
660         }
661         DOLOG( printf("n_sp = "); debug_dump_stack(n_sp-1); printf("\n") );
662         
663         iln->n_inlined_stack_cursor = n_sp;
664         assert((n_sp - iln->n_inlined_stack) <= iln->cumul_stackcount);
665 }
666
667 static void inline_resolve_block_refs(inline_target_ref **refs,basicblock *o_bptr,basicblock *n_bptr)
668 {
669         inline_target_ref *ref;
670         inline_target_ref *prev;
671
672         ref = *refs;
673         prev = NULL;
674         while (ref) {
675                 if (*(ref->ref) == o_bptr) {
676                         DOLOG(
677                                 if ((ptrint) o_bptr < (0x333+100)) { /* XXX */
678                                         printf("resolving RETURN block reference %p -> new L%03d (%p)\n",
679                                                         (void*)o_bptr,n_bptr->debug_nr,(void*)n_bptr);
680                                 }
681                                 else {
682                                         printf("resolving block reference old L%03d (%p) -> new L%03d (%p)\n",
683                                                         o_bptr->debug_nr,(void*)o_bptr,n_bptr->debug_nr,(void*)n_bptr);
684                                 }
685                         );
686                         
687                         *(ref->ref) = n_bptr;
688                         if (prev) {
689                                 prev->next = ref->next;
690                         }
691                         else {
692                                 *refs = ref->next;
693                         }
694                 }
695                 else {
696                         prev = ref;
697                 }
698                 ref = ref->next;
699         }
700 }
701
702 static basicblock * create_block(inline_node *iln,basicblock *o_bptr,inline_target_ref **refs,int indepth)
703 {
704         basicblock *n_bptr;
705         stackptr n_sp;
706         int i;
707         s4 temp;
708
709         assert(iln);
710         
711         n_bptr = iln->inlined_basicblocks_cursor++;
712         assert(n_bptr);
713         assert((n_bptr - iln->inlined_basicblocks) < iln->cumul_basicblockcount);
714         
715         /* XXX hack */
716         temp = iln->m->c_debug_nr;
717         BASICBLOCK_INIT(n_bptr,iln->m);
718         iln->m->c_debug_nr = temp;
719         
720         n_bptr->iinstr = iln->inlined_iinstr_cursor;
721         n_bptr->next = n_bptr+1;
722         n_bptr->debug_nr = iln->ctx->next_block_number++;
723         n_bptr->indepth = indepth;
724
725         if (indepth) {
726                 /* allocate stackslots */
727                 iln->n_inlined_stack_cursor += indepth;
728                 n_sp = iln->n_inlined_stack_cursor - 1;
729                 n_bptr->instack = n_sp;
730
731                 assert((n_sp - iln->n_inlined_stack) < iln->cumul_stackcount);
732
733                 /* link the stack elements */
734                 for (i=indepth-1; i>=0; --i) {
735                         n_sp->varkind = STACKVAR;
736                         n_sp->varnum = i;
737                         n_sp->prev = (i) ? n_sp-1 : NULL;
738                         n_sp->flags = 0; /* XXX */
739                         n_sp--;
740                 }
741         }
742
743         if (o_bptr) {
744                 assert(refs);
745                 inline_resolve_block_refs(refs,o_bptr,n_bptr);
746         }
747         
748         return n_bptr;
749 }
750
751 static void fill_translation_table(inline_node *iln,stackptr o_sp,stackptr n_sp,int n_depth)
752 {
753         int i;
754
755         DOLOG(
756         printf("fill_translation_table (newdepth=%d):\n",n_depth);
757         printf("\tos_sp = "); debug_dump_stack(o_sp); printf("\n");
758         printf("\tns_sp = "); debug_dump_stack(n_sp); printf("\n");
759         );
760
761         /* we must translate all stack slots that were present before the call XXX  */
762         /* and the instack of the block */
763         iln->ctx->stacktranslationstart = iln->ctx->stacktranslation + (n_depth - 1);
764
765         /* fill the translation table */
766         if (n_depth) {
767                 i = n_depth-1;
768
769                 while (o_sp) {
770                         assert(i >= 0);
771                         assert(n_sp);
772                         iln->ctx->stacktranslation[i].o_sp = o_sp;
773                         iln->ctx->stacktranslation[i].n_sp = n_sp;
774                         n_sp->flags |= (o_sp->flags & SAVEDVAR); /* XXX correct? */
775                         n_sp->type = o_sp->type; /* XXX we overwrite this anyway with STACKVAR, right? */
776                         o_sp = o_sp->prev;
777                         n_sp = n_sp->prev;
778                         i--;
779                 }
780
781                 while (n_sp) {
782                         assert(i >= 0);
783                         assert(iln->ctx->stacktranslation[i].o_sp);
784                         iln->ctx->stacktranslation[i].n_sp = n_sp;
785                         n_sp->flags |= SAVEDVAR; /* XXX this is too conservative */
786                         n_sp = n_sp->prev;
787                         i--;
788                 }
789
790                 assert(i == -1);
791         }
792 }
793
794 static void rewrite_method(inline_node *iln)
795 {
796         basicblock *o_bptr;
797         s4 len;
798         instruction *o_iptr;
799         instruction *n_iptr;
800         stackptr o_dst;
801         stackptr n_sp;
802         stackptr o_sp;
803         stackptr o_curstack;
804         stackptr o_nexttorewrite;
805         stackptr o_lasttorewrite;
806         inline_node *nextcall;
807         ptrint curreloc;
808         basicblock *n_bptr;
809         inline_block_map *bm;
810         int i;
811         int icount;
812
813         assert(iln);
814
815         n_bptr = NULL;
816         nextcall = iln->children;
817
818         /* set memory cursors */
819         iln->inlined_iinstr_cursor = iln->inlined_iinstr;
820         iln->n_inlined_stack_cursor = iln->n_inlined_stack;
821         iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
822
823         /* loop over basic blocks */
824         o_bptr = iln->m->basicblocks;
825         for (; o_bptr; o_bptr = o_bptr->next) {
826
827                 if (o_bptr->flags < BBREACHED) {
828                         DOLOG(
829                         printf("skipping old L%03d (flags=%d,type=%d,os=%p,oid=%d,ois=%p,cursor=%d,callerstack=%d) of ",
830                                         o_bptr->debug_nr,o_bptr->flags,o_bptr->type,
831                                         (void*)o_bptr->stack,o_bptr->indepth,(void*)o_bptr->instack,
832                                         DEBUG_SLOT(iln->n_inlined_stack_cursor),
833                                         DEBUG_SLOT(iln->n_callerstack));
834                         method_println(iln->m);
835                         );
836
837                         n_bptr = create_block(iln,o_bptr,&(iln->refs),o_bptr->indepth + iln->n_callerstackdepth);
838                         n_bptr->type = o_bptr->type;
839                         /* enter it in the blockmap */
840                         iln->ctx->blockmap[iln->ctx->blockmap_index].iln = iln;
841                         iln->ctx->blockmap[iln->ctx->blockmap_index].o_block = o_bptr;
842                         iln->ctx->blockmap[iln->ctx->blockmap_index++].n_block = n_bptr;
843                         n_bptr->flags = o_bptr->flags;
844                         continue;
845                 }
846
847                 assert(o_bptr->stack);
848                 
849                 len = o_bptr->icount;
850                 o_iptr = o_bptr->iinstr;
851
852                 DOLOG(
853                 printf("rewriting old L%03d (flags=%d,type=%d,os=%p,oid=%d,ois=%p,cursor=%d,callerstack=%d) of ",
854                                 o_bptr->debug_nr,o_bptr->flags,o_bptr->type,
855                                 (void*)o_bptr->stack,o_bptr->indepth,(void*)o_bptr->instack,
856                                 DEBUG_SLOT(iln->n_inlined_stack_cursor),
857                                 DEBUG_SLOT(iln->n_callerstack));
858                 method_println(iln->m);
859                 printf("o_instack: ");debug_dump_stack(o_bptr->instack);printf("\n");
860                 printf("o_callerstack: ");debug_dump_stack(iln->o_callerstack);printf("\n");
861                 );
862
863                 o_curstack = o_bptr->instack;
864
865                 /* create an inlined clone of this block */
866                 n_bptr = create_block(iln,o_bptr,&(iln->refs),o_bptr->indepth + iln->n_callerstackdepth);
867                 n_bptr->type = o_bptr->type;
868                 n_bptr->flags = o_bptr->flags;
869
870                 /* enter it in the blockmap */
871                 iln->ctx->blockmap[iln->ctx->blockmap_index].iln = iln;
872                 iln->ctx->blockmap[iln->ctx->blockmap_index].o_block = o_bptr;
873                 iln->ctx->blockmap[iln->ctx->blockmap_index++].n_block = n_bptr;
874
875                 DOLOG( debug_dump_inline_context(iln) );
876
877                 if (iln->n_callerstackdepth)
878                         iln->n_callerstack = n_bptr->instack-o_bptr->indepth;
879                 else
880                         iln->n_callerstack = NULL;
881                 fill_translation_table(iln,iln->o_callerstack,iln->n_callerstack,iln->n_callerstackdepth);
882                 fill_translation_table(iln,o_bptr->instack,n_bptr->instack,n_bptr->indepth);
883                 iln->ctx->o_translationlimit = o_bptr->stack;
884
885                 DOLOG( debug_dump_inline_context(iln) );
886
887                 /* calculate the stack element relocation */
888                 curreloc = (u1*)iln->n_inlined_stack_cursor - (u1*)o_bptr->stack;
889                 DOLOG( printf("curreloc <- %d = %p - %p\n",(int)curreloc,(void*)iln->n_inlined_stack_cursor,(void*)(u1*)o_bptr->stack) );
890
891                 o_nexttorewrite = o_bptr->stack;
892                 o_lasttorewrite = o_bptr->stack-1;
893                 assert(o_nexttorewrite);
894                         
895                 icount = 0;
896
897                 while (--len >= 0) {
898                         o_dst = o_iptr->dst;
899
900                         DOLOG( printf("o_curstack = "); debug_dump_stack(o_curstack); stack_show_icmd(o_iptr,false); printf(", dst = "); debug_dump_stack(o_dst); printf("\n") );
901
902                         if (nextcall && o_iptr == nextcall->callerins) {
903
904                                 /* rewrite stack elements produced so far in this block */
905                                 if (o_nexttorewrite <= o_lasttorewrite) {
906                                         rewrite_stack(iln, o_nexttorewrite, o_lasttorewrite, curreloc);
907                                 }
908                                 
909                                 /* write the inlining prolog */
910                                 n_sp = emit_inlining_prolog(iln,nextcall,relocate_stack_ptr(iln,o_curstack,curreloc),o_iptr);
911                                 icount += nextcall->m->parseddesc->paramcount + 1; /* XXX prolog instructions */
912
913                                 /* find the first stack slot under the arguments of the invocation */
914                                 o_sp = o_curstack;
915                                 for (i=0; i < nextcall->m->parseddesc->paramcount; ++i) {
916                                         assert(o_sp);
917                                         o_sp = o_sp->prev;
918                                 }
919                                 nextcall->o_callerstack = o_sp;
920
921                                 /* see how deep the new stack is after the arguments have been removed */
922                                 i = stack_depth(n_sp);
923                                 assert(i == stack_depth(nextcall->o_callerstack) + iln->n_callerstackdepth);
924
925                                 /* end current block */
926                                 n_bptr->icount = icount;
927                                 n_bptr->outstack = n_sp;
928                                 n_bptr->outdepth = i;
929                                 
930                                 /* caller stack depth for the callee */
931                                 assert(nextcall->n_callerstackdepth == i);
932                                 
933                                 /* set memory pointers in the callee */
934                                 nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
935                                 nextcall->n_inlined_stack = iln->n_inlined_stack_cursor;
936                                 nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
937                                 
938                                 /* recurse */
939                                 DOLOG( printf("entering inline "); stack_show_icmd(o_iptr,false); printf("\n") );
940                                 rewrite_method(nextcall);
941                                 DOLOG( printf("leaving inline "); stack_show_icmd(o_iptr,false); printf("\n") );
942
943                                 /* skip stack slots used by the inlined callee */
944                                 curreloc += (u1*)nextcall->n_inlined_stack_cursor - (u1*)iln->n_inlined_stack_cursor;
945                                 
946                                 /* update memory cursors */
947                                 assert(nextcall->inlined_iinstr_cursor == iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
948                                 /* XXX m->stackcount seems to be a conservative estimate */
949                                 assert(nextcall->n_inlined_stack_cursor <= iln->n_inlined_stack_cursor + nextcall->cumul_stackcount);
950                                 assert(nextcall->inlined_basicblocks_cursor == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
951                                 iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
952                                 iln->n_inlined_stack_cursor = nextcall->n_inlined_stack_cursor;
953                                 iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
954
955                                 /* start new block */
956                                 i = (nextcall->m->parseddesc->returntype.type == TYPE_VOID) ? 0 : 1; /* number of return slots */
957                                 assert(i == 0 || i == 1);
958                                 n_bptr = create_block(iln,(void*) (ptrint) (nextcall->depth + 0x333) /*XXX*/,
959                                                 &(nextcall->refs),nextcall->n_callerstackdepth + i);
960                                 n_bptr->flags = o_bptr->flags;
961                                 icount = 0;
962
963                                 /* skip allocated stack slots */
964                                 curreloc += sizeof(stackelement) * (n_bptr->indepth - i);
965                                 
966                                 /* fill the translation table for the slots present before the call */
967                                 n_sp = n_bptr->instack;
968                                 fill_translation_table(iln,nextcall->o_callerstack,(i) ? n_sp->prev : n_sp,nextcall->n_callerstackdepth);
969
970                                 /* the return slot */
971                                 if (i) {
972                                         assert(o_dst);
973                                         assert(n_sp);
974                                         fill_translation_table(iln,o_dst,n_sp,nextcall->n_callerstackdepth + 1);
975
976                                         o_nexttorewrite = o_dst + 1;
977                                         o_lasttorewrite = o_dst;
978                                 }
979                                 else {
980                                         /* the next chunk of stack slots start with (including) the slots produced */
981                                         /* by the invocation */
982                                         o_nexttorewrite = o_lasttorewrite + 1;
983                                         o_lasttorewrite = o_nexttorewrite - 1;
984                                 }
985                                 
986                                 DOLOG( debug_dump_inline_context(iln) );
987                                 iln->ctx->o_translationlimit = o_nexttorewrite;
988                                         
989                                 /* emit inlining epilog */
990                                 emit_inlining_epilog(iln,nextcall,n_sp,o_iptr);
991                                 icount++; /* XXX epilog instructions */
992
993                                 /* proceed to next call */
994                                 nextcall = nextcall->next;
995
996                                 DOLOG(
997                                 printf("resuming old L%03d (flags=%d,type=%d,os=%p,oid=%d,ois=%p,cursor=%d,curreloc=%d,callerstack=%d) of ",
998                                                 o_bptr->debug_nr,o_bptr->flags,o_bptr->type,
999                                                 (void*)o_bptr->stack,o_bptr->indepth,(void*)o_bptr->instack,
1000                                                 DEBUG_SLOT(iln->n_inlined_stack_cursor),(int)curreloc,
1001                                                 DEBUG_SLOT(iln->n_callerstack));
1002                                 method_println(iln->m);
1003                                 );
1004                         }
1005                         else {
1006                                 emit_instruction(iln,o_iptr,curreloc,o_curstack);
1007                                 icount++;
1008
1009                                 if (o_dst > o_lasttorewrite)
1010                                         o_lasttorewrite = o_dst;
1011                         }
1012
1013                         DOLOG( printf("o_dst = %p\n",(void*)o_dst) );
1014                         o_curstack = o_dst;
1015                         o_iptr++;
1016                 }
1017
1018                 /* end of basic block */
1019                 /* rewrite stack after last call */
1020                 if (o_nexttorewrite <= o_lasttorewrite) {
1021                         rewrite_stack(iln,o_nexttorewrite,o_lasttorewrite,curreloc);
1022                 }
1023                 n_bptr->outstack = relocate_stack_ptr(iln,o_bptr->outstack,curreloc);
1024                 n_bptr->outdepth = iln->n_callerstackdepth + o_bptr->outdepth;
1025                 assert(n_bptr->outdepth == stack_depth(n_bptr->outstack));
1026 #if 0
1027                 if (n_bptr->outstack) {
1028                         assert(curreloc);
1029                         n_bptr->outstack += curreloc;
1030                 }
1031 #endif
1032                 n_bptr->icount = icount;
1033
1034                 n_iptr = iln->inlined_iinstr_cursor - 1;
1035                 if (n_iptr->opc == ICMD_INLINE_GOTO) {
1036                         DOLOG( printf("creating stack slot for ICMD_INLINE_GOTO\n") );
1037                         n_sp = iln->n_inlined_stack_cursor++;
1038                         assert(n_iptr->dst);
1039                         *n_sp = *n_iptr->dst;
1040                         n_sp->prev = iln->n_callerstack;
1041                         n_iptr->dst = n_sp;
1042
1043                         n_bptr->outdepth = iln->n_callerstackdepth + 1;
1044                         n_bptr->outstack = n_sp;
1045                 }
1046         }
1047
1048         bm = iln->ctx->blockmap;
1049         for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
1050                 assert(bm->iln && bm->o_block && bm->n_block);
1051                 if (bm->iln != iln)
1052                         continue;
1053                 inline_resolve_block_refs(&(iln->refs),iln->ctx->blockmap[i].o_block,iln->ctx->blockmap[i].n_block);
1054         }
1055
1056 #ifndef NDEBUG
1057         if (iln->refs) {
1058                 inline_target_ref *ref;
1059                 ref = iln->refs;
1060                 while (ref) {
1061                         if (!iln->depth || *(ref->ref) != (void*) (ptrint) (0x333 + iln->depth) /* XXX */) {
1062                                 DOLOG( printf("XXX REMAINING REF at depth %d: %p\n",iln->depth,(void*)*(ref->ref)) );
1063                                 assert(false);
1064                         }
1065                         ref = ref->next;
1066                 }
1067         }
1068 #endif
1069 }
1070
1071 static basicblock * inline_map_block(inline_node *iln,basicblock *o_block,inline_node *targetiln)
1072 {
1073         inline_block_map *bm;
1074         inline_block_map *bmend;
1075         
1076         assert(iln);
1077         assert(targetiln);
1078         
1079         if (!o_block)
1080                 return NULL;
1081
1082         bm = iln->ctx->blockmap;
1083         bmend = bm + iln->ctx->blockmap_index;
1084
1085         while (bm < bmend) {
1086                 assert(bm->iln && bm->o_block && bm->n_block);
1087                 if (bm->o_block == o_block && bm->iln == targetiln)
1088                         return bm->n_block;
1089                 bm++;
1090         }
1091
1092         assert(false);
1093         return NULL; /* not reached */
1094 }
1095
1096 static exceptiontable * inline_exception_tables(inline_node *iln,exceptiontable *n_extable,exceptiontable **prevextable)
1097 {
1098         inline_node *child;
1099         exceptiontable *et;
1100         int i;
1101         
1102         assert(iln);
1103         assert(n_extable);
1104         assert(prevextable);
1105
1106         child = iln->children;
1107         if (child) {
1108                 do {
1109                         n_extable = inline_exception_tables(child,n_extable,prevextable);
1110                         child = child->next;
1111                 } while (child != iln->children);
1112         }
1113
1114         et = iln->m->exceptiontable;
1115         for (i=0; i<iln->m->exceptiontablelength; ++i) {
1116                 assert(et);
1117                 memset(n_extable,0,sizeof(exceptiontable));
1118                 n_extable->startpc = et->startpc;
1119                 n_extable->endpc = et->endpc;
1120                 n_extable->handlerpc = et->handlerpc;
1121                 n_extable->start = inline_map_block(iln,et->start,iln);
1122                 n_extable->end = inline_map_block(iln,et->end,iln);
1123                 n_extable->handler = inline_map_block(iln,et->handler,iln);
1124                 n_extable->catchtype = et->catchtype;
1125
1126                 if (*prevextable) {
1127                         (*prevextable)->down = n_extable;
1128                 }
1129                 *prevextable = n_extable;
1130                 
1131                 n_extable++;
1132                 et++;
1133         }
1134
1135         if (iln->handler_monitorexit) {
1136                 exceptiontable **activehandlers;
1137                         
1138                 memset(n_extable,0,sizeof(exceptiontable));
1139                 n_extable->startpc = 0; /* XXX */
1140                 n_extable->endpc = 0; /* XXX */
1141                 n_extable->handlerpc = 0; /* XXX */
1142                 n_extable->start = iln->inlined_basicblocks;
1143                 n_extable->end = iln->inlined_basicblocks_cursor;
1144                 n_extable->handler = iln->handler_monitorexit;
1145                 n_extable->catchtype.any = NULL; /* finally */
1146
1147                 if (*prevextable) {
1148                         (*prevextable)->down = n_extable;
1149                 }
1150                 *prevextable = n_extable;
1151                 
1152                 n_extable++;
1153
1154                 activehandlers = iln->o_handlers;
1155                 while (*activehandlers) {
1156
1157                         assert(iln->parent);
1158
1159                         memset(n_extable,0,sizeof(exceptiontable));
1160                         n_extable->startpc = 0; /* XXX */
1161                         n_extable->endpc = 0; /* XXX */
1162                         n_extable->handlerpc = 0; /* XXX */
1163                         n_extable->start = iln->handler_monitorexit;
1164                         n_extable->end = iln->handler_monitorexit + 1;
1165                         n_extable->handler = inline_map_block(iln->parent,(*activehandlers)->handler,iln->parent);
1166                         n_extable->catchtype = (*activehandlers)->catchtype;
1167
1168                         if (*prevextable) {
1169                                 (*prevextable)->down = n_extable;
1170                         }
1171                         *prevextable = n_extable;
1172
1173                         n_extable++;
1174                         activehandlers++;
1175                 }
1176                 
1177         }
1178
1179         return n_extable;
1180 }
1181
1182 static void inline_locals(inline_node *iln,registerdata *rd)
1183 {
1184         int i;
1185         int t;
1186         inline_node *child;
1187
1188         assert(iln);
1189         assert(rd);
1190
1191         child = iln->children;
1192         if (child) {
1193                 do {
1194                         inline_locals(child,rd);
1195                         child = child->next;
1196                 } while (child != iln->children);
1197         }
1198
1199         assert(iln->regdata);
1200
1201         for (i=0; i<iln->m->maxlocals; ++i) {
1202                 for (t=TYPE_INT; t<=TYPE_ADR; ++t) {
1203                         DOLOG( printf("local %d type=%d in ",i,iln->regdata->locals[i][t].type); method_println(iln->m); );
1204                         if (iln->regdata->locals[i][t].type >= 0) {
1205                                 rd->locals[iln->localsoffset + i][t].type = iln->regdata->locals[i][t].type;
1206                                 rd->locals[iln->localsoffset + i][t].flags |= iln->regdata->locals[i][t].flags;
1207                         }
1208                 }
1209         }
1210
1211         if (iln->regdata->memuse > rd->memuse)
1212                 rd->memuse = iln->regdata->memuse;
1213         if (iln->regdata->argintreguse > rd->argintreguse)
1214                 rd->argintreguse = iln->regdata->argintreguse;
1215         if (iln->regdata->argfltreguse > rd->argfltreguse)
1216                 rd->argfltreguse = iln->regdata->argfltreguse;
1217 }
1218
1219 static void inline_stack_interfaces(inline_node *iln,registerdata *rd)
1220 {
1221         int i;
1222         int d;
1223         basicblock *bptr;
1224         stackptr sp;
1225
1226         assert(iln);
1227         assert(rd);
1228         assert(rd->interfaces);
1229
1230         bptr = iln->inlined_basicblocks;
1231         for (i=0; i<iln->cumul_basicblockcount; ++i, ++bptr) {
1232                 DOLOG( printf("INLINE STACK INTERFACE block L%03d\n",bptr->debug_nr) );
1233                 DOLOG( printf("\toutstack = ");debug_dump_stack(bptr->outstack);printf("\n") );
1234                 DOLOG( printf("\tinstack = ");debug_dump_stack(bptr->outstack);printf("\n") );
1235
1236                 assert(bptr->outdepth == stack_depth(bptr->outstack));
1237                 assert(bptr->indepth == stack_depth(bptr->instack));
1238                 
1239                 sp = bptr->outstack;
1240                 d = bptr->outdepth - 1;
1241                 while (sp) {
1242                         if ((sp->varkind == STACKVAR) && (sp->varnum > d)) {
1243                                 sp->varkind = TEMPVAR;
1244                         }
1245                         else {
1246                                 sp->varkind = STACKVAR;
1247                                 sp->varnum = d;
1248                         }
1249                         DOLOG( printf("INLINE STACK INTERFACE L%03d outstack d=%d varkind=%d varnum=%d type=%d flags=%01x\n",
1250                                         bptr->debug_nr,d,sp->varkind,sp->varnum,sp->type,sp->flags) );
1251                         rd->interfaces[d][sp->type].type = sp->type;
1252                         rd->interfaces[d][sp->type].flags |= sp->flags;
1253                         d--;
1254                         sp = sp->prev;
1255                 }
1256
1257                 sp = bptr->instack;
1258                 d = bptr->indepth - 1;
1259                 while (sp) {
1260                         rd->interfaces[d][sp->type].type = sp->type;
1261                         if (sp->varkind == STACKVAR && (sp->flags & SAVEDVAR)) {
1262                                 rd->interfaces[d][sp->type].flags |= SAVEDVAR;
1263                         }
1264                         DOLOG( printf("INLINE STACK INTERFACE L%03d instack d=%d varkind=%d varnum=%d type=%d flags=%01x\n",
1265                                         bptr->debug_nr,d,sp->varkind,sp->varnum,sp->type,sp->flags) );
1266                         d--;
1267                         sp = sp->prev;
1268                 }
1269         }
1270 }
1271
1272 static bool inline_inline_intern(methodinfo *m,jitdata *jd, inline_node *iln)
1273 {
1274         basicblock *bptr;
1275         s4 len;
1276         instruction *iptr;
1277         stackptr o_dst;
1278         stackptr o_curstack;
1279         int opcode;                                   /* invocation opcode */
1280         methodinfo *callee;
1281         inline_node *calleenode;
1282         inline_node *active;
1283         stackptr sp;
1284         s4 i;
1285         bool isstatic;
1286         exceptiontable **handlers;
1287         s4 nhandlers;
1288
1289         assert(jd);
1290         assert(iln);
1291
1292         /* initialize cumulative counters */
1293         
1294         iln->cumul_maxstack = iln->n_callerstackdepth + m->maxstack + 1 /* XXX builtins */;
1295         iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
1296         iln->cumul_exceptiontablelength += m->exceptiontablelength;
1297
1298         /* iterate over basic blocks */
1299
1300         bptr = m->basicblocks;
1301         for (; bptr; bptr = bptr->next) {
1302
1303                 iln->cumul_basicblockcount++;
1304
1305                 /* extra stackslots */
1306                 iln->cumul_stackcount += iln->n_callerstackdepth;
1307
1308                 if (bptr->flags < BBREACHED)
1309                         continue;
1310
1311                 /* allocate the buffer of active exception handlers */
1312                 /* XXX this wastes some memory, but probably it does not matter */
1313         
1314                 handlers = DMNEW(exceptiontable*, m->exceptiontablelength + 1);
1315
1316                 /* determine the active exception handlers for this block     */
1317                 /* XXX maybe the handlers of a block should be part of our IR */
1318                 nhandlers = 0;
1319                 for (i = 0; i < m->exceptiontablelength; ++i) {
1320                         if ((m->exceptiontable[i].start <= bptr) && (m->exceptiontable[i].end > bptr)) {
1321                                 handlers[nhandlers++] = m->exceptiontable + i;
1322                         }
1323                 }
1324                 handlers[nhandlers] = NULL;
1325
1326                 assert(bptr->stack);
1327                 
1328                 len = bptr->icount;
1329                 iptr = bptr->iinstr;
1330                 o_curstack = bptr->instack;
1331
1332                 iln->instructioncount += len;
1333                 iln->cumul_instructioncount += len;
1334
1335 #if 0
1336                 printf("ADD INSTRUCTIONS [%d]: %d, count=%d, cumulcount=%d\n",
1337                                 iln->depth,len,iln->instructioncount,iln->cumul_instructioncount);
1338 #endif
1339
1340                 while (--len >= 0) {
1341
1342                         opcode = iptr->opc;
1343                         o_dst = iptr->dst;
1344
1345                         switch (opcode) {
1346                                 case ICMD_IINC:
1347                                         /* XXX we cannot deal with IINC's stack hacking */
1348                                         return false;
1349
1350                                 case ICMD_LOOKUPSWITCH:
1351                                 case ICMD_TABLESWITCH:
1352                                         /* XXX these are not implemented, yet. */
1353                                         return false;
1354                                 
1355                                 /****************************************/
1356                                 /* INVOKATIONS                          */
1357
1358                                 case ICMD_INVOKEVIRTUAL:
1359                                 case ICMD_INVOKESPECIAL:
1360                                 case ICMD_INVOKESTATIC:
1361                                 case ICMD_INVOKEINTERFACE:
1362                                         callee = (methodinfo *) iptr[0].val.a;
1363
1364                                         if (callee) {
1365                                                 if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE) || opcode == ICMD_INVOKESPECIAL)
1366                                                     && !(callee->flags & (ACC_NATIVE))) 
1367                                                 {
1368                                                         if (iln->depth < 3) {
1369                                                                 for (active = iln; active; active = active->parent) {
1370                                                                         if (callee == active->m) {
1371                                                                                 DOLOG( printf("RECURSIVE!\n") );
1372                                                                                 goto dont_inline;
1373                                                                         }
1374                                                                 }
1375                                                 
1376                                                                 calleenode = DNEW(inline_node);
1377                                                                 memset(calleenode,0,sizeof(inline_node));
1378                                                                 
1379                                                                 calleenode->ctx = iln->ctx;
1380                                                                 calleenode->m = callee;
1381                                                                 calleenode->synchronize = (callee->flags & ACC_SYNCHRONIZED);
1382                                                                 isstatic = (callee->flags & ACC_STATIC);
1383
1384                                                                 if (!inline_jit_compile(calleenode))
1385                                                                         return false;
1386                                                                 
1387                                                                 /* info about the call site */
1388                                                                 calleenode->depth = iln->depth+1;
1389                                                                 calleenode->callerblock = bptr;
1390                                                                 calleenode->callerins = iptr;
1391                                                                 calleenode->callerpc = iptr - m->basicblocks->iinstr;
1392                                                                 calleenode->o_handlers = handlers;
1393                                                                 
1394                                                                 /* info about the callee */
1395                                                                 calleenode->localsoffset = iln->localsoffset + m->maxlocals;
1396                                                                 calleenode->prolog_instructioncount = callee->parseddesc->paramcount;
1397                                                                 calleenode->epilog_instructioncount = 0;
1398                                                                 calleenode->extra_instructioncount = 0;
1399
1400                                                                 if (calleenode->synchronize) {
1401                                                                         methoddesc         *md;
1402                                                                         builtintable_entry *bte;
1403                                                                         
1404                                                                         /* and exception handler */
1405                                                                         /* ALOAD, builtin_monitorexit, ATHROW */
1406                                                                         calleenode->extra_instructioncount += 3;
1407                                                                         /* stack elements used in handler */
1408                                                                         iln->cumul_stackcount += 2;
1409
1410                                                                         /* exception table entries */
1411                                                                         iln->cumul_exceptiontablelength += 1 + nhandlers;
1412
1413                                                                         bte = builtintable_get_internal(BUILTIN_monitorenter);
1414                                                                         md = bte->md;
1415                                                                         if (md->memuse > calleenode->regdata->memuse)
1416                                                                                 calleenode->regdata->memuse = md->memuse;
1417                                                                         if (md->argintreguse > calleenode->regdata->argintreguse)
1418                                                                                 calleenode->regdata->argintreguse = md->argintreguse;
1419
1420                                                                         /* XXX
1421                                                                         bte = builtintable_get_internal(BUILTIN_staticmonitorenter);
1422                                                                         md = bte->md;
1423                                                                         if (md->memuse > calleenode->regdata->memuse)
1424                                                                                 calleenode->regdata->memuse = md->memuse;
1425                                                                         if (md->argintreguse > calleenode->regdata->argintreguse)
1426                                                                                 calleenode->regdata->argintreguse = md->argintreguse;
1427                                                                                 */
1428
1429                                                                         bte = builtintable_get_internal(BUILTIN_monitorexit);
1430                                                                         md = bte->md;
1431                                                                         if (md->memuse > calleenode->regdata->memuse)
1432                                                                                 calleenode->regdata->memuse = md->memuse;
1433                                                                         if (md->argintreguse > calleenode->regdata->argintreguse)
1434                                                                                 calleenode->regdata->argintreguse = md->argintreguse;
1435
1436                                                                         iln->ctx->calls_others = true;
1437                                                                 }
1438
1439                                                                 calleenode->stackcount = callee->stackcount;
1440                                                                 calleenode->cumul_stackcount = callee->stackcount;
1441
1442                                                                 /* see how deep the stack is below the arguments */
1443                                                                 sp = o_curstack;
1444                                                                 for (i=0; sp; sp = sp->prev)
1445                                                                         i++;
1446                                                                 calleenode->n_callerstackdepth = iln->n_callerstackdepth + i - callee->parseddesc->paramcount;
1447
1448                                                                 insert_inline_node(iln,calleenode);
1449
1450                                                                 if (!inline_inline_intern(callee,jd,calleenode))
1451                                                                         return false;
1452
1453                                                                 if (calleenode->synchronize) {
1454                                                                         /* add exception handler block */
1455                                                                         iln->ctx->master->cumul_basicblockcount++;
1456                                                                 }
1457
1458                                                                 iln->cumul_instructioncount += calleenode->prolog_instructioncount;
1459                                                                 iln->cumul_instructioncount += calleenode->epilog_instructioncount;
1460                                                                 iln->cumul_instructioncount += calleenode->extra_instructioncount;
1461                                                                 iln->cumul_instructioncount += calleenode->cumul_instructioncount - 1/*invoke*/ + 2 /*INLINE_START|END*/;
1462                                                                 iln->cumul_stackcount += calleenode->cumul_stackcount;
1463
1464                                                                 /* XXX extra block after inlined call */
1465                                                                 iln->cumul_stackcount += calleenode->n_callerstackdepth;
1466                                                                 iln->cumul_basicblockcount += 1;
1467                                                                 
1468                                                                 iln->cumul_basicblockcount += calleenode->cumul_basicblockcount;
1469                                                                 iln->cumul_exceptiontablelength += calleenode->cumul_exceptiontablelength;
1470                                                                 if (calleenode->cumul_maxstack > iln->cumul_maxstack)
1471                                                                         iln->cumul_maxstack = calleenode->cumul_maxstack;
1472                                                                 if (calleenode->cumul_maxlocals > iln->cumul_maxlocals)
1473                                                                         iln->cumul_maxlocals = calleenode->cumul_maxlocals;
1474                                                         }
1475                                                 }
1476                                         }
1477 dont_inline:
1478
1479                                         break;
1480                         }
1481
1482                         o_curstack = o_dst;
1483                         ++iptr;
1484                 }
1485
1486                 /* end of basic block */
1487         }       
1488
1489         return true;
1490 }
1491
1492 static void inline_write_exception_handlers(inline_node *master,inline_node *iln)
1493 {
1494         basicblock *n_bptr;
1495         stackptr n_curstack;
1496         instruction *n_ins;
1497         inline_node *child;
1498         builtintable_entry *bte;
1499         
1500         child = iln->children;
1501         if (child) {
1502                 do {
1503                         inline_write_exception_handlers(master,child);
1504                         child = child->next;
1505                 } while (child != iln->children);
1506         }
1507
1508         if (iln->synchronize) {
1509                 /* create the monitorexit handler */
1510                 n_bptr = create_block(master,NULL,NULL,1 /*XXX*/);
1511                 n_bptr->type = BBTYPE_EXH;
1512                 n_bptr->flags = BBFINISHED;
1513
1514                 iln->handler_monitorexit = n_bptr;
1515                 
1516                 n_curstack = n_bptr->instack;
1517
1518                 /* ACONST / ALOAD */
1519
1520                 n_curstack = inline_new_stackslot(master,n_curstack,TYPE_ADR);
1521                 
1522                 n_ins = master->inlined_iinstr_cursor++;
1523                 if (iln->m->flags & ACC_STATIC) {
1524                         n_ins->opc = ICMD_ACONST;
1525                         n_ins->val.a = iln->m->class;
1526                         n_ins->target = class_get_self_classref(iln->m->class);
1527                 }
1528                 else {
1529                         n_ins->opc = ICMD_ALOAD;
1530                         n_ins->op1 = iln->localsoffset; /* XXX */
1531                 }
1532                 n_ins->dst = n_curstack;
1533                 n_ins->line = 0;
1534
1535                 /* MONITOREXIT */
1536
1537                 n_curstack = n_curstack->prev;
1538
1539                 bte = builtintable_get_internal(BUILTIN_monitorexit);
1540
1541                 n_ins = master->inlined_iinstr_cursor++;
1542                 n_ins->opc = ICMD_BUILTIN;
1543                 n_ins->val.a = bte;
1544                 n_ins->dst = n_curstack;
1545                 n_ins->line = 0;
1546
1547                 /* ATHROW */
1548                 
1549                 n_curstack = n_curstack->prev;
1550                 
1551                 n_ins = master->inlined_iinstr_cursor++;
1552                 n_ins->opc = ICMD_ATHROW;
1553                 n_ins->dst = n_curstack;
1554                 n_ins->line = 0;
1555
1556                 /* close basic block */
1557
1558                 n_bptr->outstack = n_curstack;
1559                 n_bptr->outdepth = stack_depth(n_curstack); /* XXX */
1560                 n_bptr->icount = 3;
1561         }
1562 }
1563
1564 static bool test_inlining(inline_node *iln,jitdata *jd,
1565                 methodinfo **resultmethod, jitdata **resultjd)
1566 {
1567         instruction *n_ins;
1568         stackptr n_stack;
1569         basicblock *n_bb;
1570         methodinfo *n_method;
1571         exceptiontable *n_ext;
1572         exceptiontable *prevext;
1573         codegendata *n_cd;
1574         registerdata *n_rd;
1575         jitdata *n_jd;
1576         
1577
1578         static int debug_verify_inlined_code = 1;
1579 #ifndef NDEBUG
1580         static int debug_compile_inlined_code_counter = 0;
1581 #endif
1582
1583         assert(iln && jd && resultmethod && resultjd);
1584
1585         *resultmethod = iln->m;
1586         *resultjd = jd;
1587
1588 #if 0
1589         if (debug_compile_inlined_code_counter >5)
1590                 return false;
1591 #endif
1592
1593         n_ins = DMNEW(instruction,iln->cumul_instructioncount);
1594         iln->inlined_iinstr = n_ins;
1595
1596         n_stack = DMNEW(stackelement,iln->cumul_stackcount);
1597         iln->n_inlined_stack = n_stack;
1598         iln->ctx->n_debug_stackbase = n_stack;
1599
1600         n_bb = DMNEW(basicblock,iln->cumul_basicblockcount);
1601         iln->inlined_basicblocks = n_bb;
1602
1603         iln->ctx->blockmap = DMNEW(inline_block_map,iln->cumul_basicblockcount);
1604
1605         rewrite_method(iln);
1606         inline_write_exception_handlers(iln,iln);
1607
1608         /* end of basic blocks */
1609         if (iln->inlined_basicblocks_cursor > iln->inlined_basicblocks) {
1610                 iln->inlined_basicblocks_cursor[-1].next = NULL;
1611         }
1612
1613         if (iln->cumul_exceptiontablelength) {
1614                 exceptiontable *tableend;
1615                 
1616                 n_ext = DMNEW(exceptiontable,iln->cumul_exceptiontablelength);
1617                 prevext = NULL;
1618                 tableend = inline_exception_tables(iln,n_ext,&prevext);
1619                 assert(tableend == n_ext + iln->cumul_exceptiontablelength);
1620                 if (prevext)
1621                         prevext->down = NULL;
1622         }
1623         else {
1624                 n_ext = NULL;
1625         }
1626
1627         /*******************************************************************************/
1628
1629         n_method = NEW(methodinfo);
1630         memcpy(n_method,iln->m,sizeof(methodinfo));
1631         n_method->maxstack = iln->cumul_maxstack; /* XXX put into cd,rd */
1632         n_method->maxlocals = iln->cumul_maxlocals;
1633         n_method->basicblockcount = iln->cumul_basicblockcount;
1634         n_method->basicblocks = iln->inlined_basicblocks;
1635         n_method->basicblockindex = NULL;
1636         n_method->instructioncount = iln->cumul_instructioncount;
1637         n_method->instructions = iln->inlined_iinstr;
1638         n_method->stackcount = iln->cumul_stackcount;
1639         n_method->stack = iln->n_inlined_stack;
1640
1641         n_method->exceptiontablelength = iln->cumul_exceptiontablelength;
1642         n_method->exceptiontable = n_ext;
1643         n_method->linenumbercount = 0;
1644
1645         n_jd = DNEW(jitdata);
1646         n_jd->flags = 0;
1647         n_jd->m = n_method;
1648
1649         if (iln->ctx->calls_others) {
1650                 n_method->isleafmethod = false;
1651         }
1652         
1653         n_jd->code = code_codeinfo_new(n_method);
1654
1655         n_cd = DNEW(codegendata);
1656         n_jd->cd = n_cd;
1657         memcpy(n_cd,jd->cd,sizeof(codegendata));
1658         n_cd->method = n_method;
1659         n_cd->maxstack = n_method->maxstack;
1660         n_cd->maxlocals = n_method->maxlocals;
1661         n_cd->exceptiontablelength = n_method->exceptiontablelength;
1662         n_cd->exceptiontable = n_method->exceptiontable;
1663
1664         n_rd = DNEW(registerdata);
1665         n_jd->rd = n_rd;
1666         reg_setup(n_jd);
1667
1668         iln->regdata = jd->rd;
1669         inline_locals(iln,n_rd);
1670         DOLOG( printf("INLINING STACK INTERFACES FOR "); method_println(iln->m) );
1671         inline_stack_interfaces(iln,n_rd);
1672         
1673         if (debug_verify_inlined_code) {
1674                 debug_verify_inlined_code = 0;
1675                 DOLOG( printf("VERIFYING INLINED RESULT...\n") );
1676                 if (!typecheck(n_jd)) {
1677                         *exceptionptr = NULL;
1678                         DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
1679                         return false;
1680                 }
1681                 else {
1682                         DOLOG( printf("VERIFICATION PASSED.\n") );
1683                 }
1684                 debug_verify_inlined_code = 1;
1685         }
1686
1687 #ifndef NDEBUG
1688 #if 1
1689         if (n_method->instructioncount >= inline_debug_min_size && n_method->instructioncount <= inline_debug_max_size) {
1690            if (debug_compile_inlined_code_counter >= inline_debug_start_counter 
1691                            && debug_compile_inlined_code_counter <= inline_debug_end_counter) 
1692 #else
1693         if (
1694                 (strcmp(n_method->class->name->text,"java/lang/reflect/Array") == 0 &&
1695                 strcmp(n_method->name->text,"<clinit>") == 0 &&
1696                 strcmp(n_method->descriptor->text,"()V") == 0)
1697                 ||
1698                 (strcmp(n_method->class->name->text,"java/lang/VMClassLoader") == 0 &&
1699                 strcmp(n_method->name->text,"getSystemClassLoader") == 0 &&
1700                 strcmp(n_method->descriptor->text,"()Ljava/lang/ClassLoader;") == 0)
1701                 ) 
1702         
1703         {
1704 #endif
1705 #endif /* NDEBUG */
1706            {
1707                         *resultmethod = n_method;
1708                         *resultjd = n_jd;
1709
1710 #ifndef NDEBUG
1711                         inline_count_methods++;
1712                         if (inline_debug_log_names)
1713                                 method_println(n_method);
1714
1715                         DOLOG(
1716                         printf("==== %d.INLINE ==================================================================\n",debug_compile_inlined_code_counter);
1717                         method_println(n_method);
1718                         stack_show_method(jd);
1719                         dump_inline_tree(iln);
1720                         stack_show_method(n_jd);
1721                         debug_dump_inlined_code(iln,n_method,n_cd,n_rd);
1722                         printf("-------- DONE -----------------------------------------------------------\n");
1723                         fflush(stdout);
1724                         );
1725 #endif
1726            }
1727
1728 #ifndef NDEBUG
1729                 debug_compile_inlined_code_counter++;
1730         }
1731 #endif
1732         return true;
1733 }
1734
1735 bool inline_inline(jitdata *jd, methodinfo **resultmethod, 
1736                                    jitdata **resultjd)
1737 {
1738         inline_node *iln;
1739         methodinfo *m;
1740
1741         m = jd->m;
1742
1743         *resultmethod = m;
1744         *resultjd = jd;
1745
1746 #if 0
1747         printf("==== INLINE ==================================================================\n");
1748         method_println(m);
1749         stack_show_method(jd);
1750 #endif
1751         
1752         iln = DNEW(inline_node);
1753         memset(iln,0,sizeof(inline_node));
1754
1755         iln->ctx = (inline_context *) DMNEW(u1,sizeof(inline_context) + sizeof(inline_stack_translation) * 1000 /* XXX */);
1756         memset(iln->ctx,0,sizeof(inline_context));
1757         iln->ctx->master = iln;
1758         iln->ctx->stacktranslationstart = iln->ctx->stacktranslation - 1;
1759         iln->ctx->calls_others = false;
1760         iln->m = m;             
1761
1762         /* we cannot use m->instructioncount because it may be greater than 
1763          * the actual number of instructions in the basic blocks. */
1764         iln->instructioncount = 0;
1765         iln->cumul_instructioncount = 0;
1766
1767         iln->stackcount = m->stackcount;
1768         iln->cumul_stackcount = m->stackcount;
1769
1770         if (inline_inline_intern(m,jd,iln)) {
1771         
1772 #if 0
1773                 printf("==== TEST INLINE =============================================================\n");
1774                 method_println(m);
1775 #endif
1776
1777                 if (iln->children)
1778                         test_inlining(iln,jd,resultmethod,resultjd);
1779         }
1780
1781 #if 0
1782         printf("-------- DONE -----------------------------------------------------------\n");
1783         fflush(stdout);
1784 #endif
1785
1786         return true;
1787 }
1788
1789 /*
1790  * These are local overrides for various environment variables in Emacs.
1791  * Please do not remove this and leave it at the end of the file, where
1792  * Emacs will automagically detect them.
1793  * ---------------------------------------------------------------------
1794  * Local variables:
1795  * mode: c
1796  * indent-tabs-mode: t
1797  * c-basic-offset: 4
1798  * tab-width: 4
1799  * End:
1800  * vim:noexpandtab:sw=4:ts=4:
1801  */