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