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