* src/vm/jit/inline/inline.c: Ported to the new IR. There are some
authoredwin <none@none>
Sun, 5 Nov 2006 10:40:15 +0000 (10:40 +0000)
committeredwin <none@none>
Sun, 5 Nov 2006 10:40:15 +0000 (10:40 +0000)
checkins missing to make it linkable, though.
* src/vm/jit/inline/inline_debug.inc: Likewise.

src/vm/jit/inline/inline.c
src/vm/jit/inline/inline_debug.inc

index 7a5a7a9408ddad862970b5387e4cbf9445663ad2..85a0ca9d91c3182443d1960a177ac899fbd5c4cc 100644 (file)
@@ -1,4 +1,4 @@
-/* src/vm/jit/inline/inline.c - code inliner
+/* src/vm/jit/inline/inline.c - method inlining
 
    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
@@ -28,7 +28,7 @@
 
    Changes:
 
-   $Id: inline.c 5785 2006-10-15 22:25:54Z edwin $
+   $Id: inline.c 5911 2006-11-05 10:40:15Z edwin $
 
 */
 
@@ -67,7 +67,8 @@
 # include "threads/native/threads.h"
 #endif
 
-#ifndef NDEBUG
+#if !defined(NDEBUG)
+#define INLINE_VERBOSE
 bool inline_debug_log = 0;
 bool inline_debug_log_names = 0;
 int inline_debug_start_counter = 0;
@@ -80,54 +81,60 @@ int inline_count_methods = 0;
 #define DOLOG(code)
 #endif
 
+
+/* types **********************************************************************/
+
 typedef struct inline_node inline_node;
 typedef struct inline_target_ref inline_target_ref;
 typedef struct inline_context inline_context;
-typedef struct inline_stack_translation inline_stack_translation;
 typedef struct inline_block_map inline_block_map;
 
 struct inline_node {
        inline_context *ctx;
-       
+
+       jitdata *jd;
        methodinfo *m;
        inline_node *children;
-       inline_node *next;
-       inline_node *prev;
-       int depth;
-       
+       inline_node *next;                             /* next node at this depth */
+       inline_node *prev;                             /* prev node at this depth */
+       int depth;                                  /* inlining depth, 0 for root */
+
        /* info about the call site (if depth > 0)*/
-       inline_node *parent;
-       basicblock *callerblock;
-       instruction *callerins;
+       inline_node *parent;                /* node of the caller (NULL for root) */
+       basicblock *callerblock;         /* original block containing the INVOKE* */
+       instruction *callerins;               /* the original INVOKE* instruction */
        s4 callerpc;
-       stackptr n_callerstack;
-       int n_callerstackdepth;
-       stackptr o_callerstack;
-       exceptiontable **o_handlers;
+       s4 *n_passthroughvars;
+       int n_passthroughcount;
+       int n_selfpassthroughcount;  /* # of pass-through vars of the call itself */
+       exception_entry **o_handlers;
+       int n_handlercount;                 /* # of handlers protecting this call */
+       int n_resultlocal;
+       int synclocal;                    /* variable used for synchr., or UNUSED */
+
+       bool blockbefore;                  /* block boundary before inlined body? */
+       bool blockafter;                   /* block boundary after inlined body?  */
 
        /* info about the callee */
        int localsoffset;
-       int prolog_instructioncount;
-       int epilog_instructioncount;
+       int prolog_instructioncount;         /* # of ICMDs in the inlining prolog */
+       int epilog_instructioncount;         /* # of ICMDs in the inlining epilog */
        int extra_instructioncount;
        int instructioncount;
-       int stackcount;
-       bool synchronize;
-       basicblock *handler_monitorexit;
-       
+       bool synchronize;                /* do we have to synchronize enter/exit? */
+       basicblock *handler_monitorexit;     /* handler for synchronized inlinees */
+       s4 *varmap;
+
        /* cumulative values */
-       int cumul_instructioncount;
-       int cumul_stackcount;
-       int cumul_basicblockcount;
-       int cumul_maxstack;
+       int cumul_instructioncount;  /* ICMDs in this node and its children       */
+       int cumul_basicblockcount;   /* BBs started by this node and its children */
+       int cumul_blockmapcount;
        int cumul_maxlocals;
        int cumul_exceptiontablelength;
 
        /* output */
        instruction *inlined_iinstr;
        instruction *inlined_iinstr_cursor;
-       stackptr n_inlined_stack;
-       stackptr n_inlined_stack_cursor;
        basicblock *inlined_basicblocks;
        basicblock *inlined_basicblocks_cursor;
 
@@ -137,6 +144,10 @@ struct inline_node {
        /* temporary */
        inline_target_ref *refs;
        instruction *inline_start_instruction;
+
+       /* XXX debug */
+       char *indent;
+       int debugnr;
 };
 
 struct inline_target_ref {
@@ -145,11 +156,6 @@ struct inline_target_ref {
        basicblock *target;
 };
 
-struct inline_stack_translation {
-       stackptr o_sp;
-       stackptr n_sp;
-};
-
 struct inline_block_map {
        inline_node *iln;
        basicblock *o_block;
@@ -159,48 +165,51 @@ struct inline_block_map {
 struct inline_context {
        inline_node *master;
 
+       jitdata *resultjd;
+
        int next_block_number;
        inline_block_map *blockmap;
        int blockmap_index;
 
+       int maxinoutdepth;
+
        bool calls_others;
-       
-       stackptr o_translationlimit; /* if a stackptr is smaller than this, look it up in the table */
-       stackptr n_debug_stackbase;
-       inline_stack_translation *stacktranslationstart;
 
-       inline_stack_translation stacktranslation[1]; /* XXX VARIABLE LENGTH! */
+       int next_debugnr; /* XXX debug */
 };
 
-static int stack_depth(stackptr sp)
-{
-       int depth = 0;
-       while (sp) {
-               depth++;
-               sp = sp->prev;
-       }
-       return depth;
-}
 
-#ifndef NDEBUG
+/* prototypes *****************************************************************/
+
+static bool inline_inline_intern(methodinfo *m, inline_node *iln);
+static void inline_post_process(jitdata *jd);
+
+
+/* debug helpers **************************************************************/
+
+#if !defined(NDEBUG)
 #include "inline_debug.inc"
 
 void inline_print_stats()
 {
-       printf("inlined callers: %d\n",inline_count_methods);
+       printf("inlined callers: %d\n", inline_count_methods);
 }
 #endif
 
+
+/* compilation of callees *****************************************************/
+
 static bool inline_jit_compile_intern(jitdata *jd)
 {
        methodinfo *m;
-       
+
+       /* XXX should share code with jit.c */
+
        assert(jd);
-       
+
        /* XXX initialize the static function's class */
 
        m = jd->m;
-       m->isleafmethod = true;
 
        /* call the compiler passes ***********************************************/
 
@@ -220,12 +229,14 @@ static bool inline_jit_compile_intern(jitdata *jd)
        return true;
 }
 
+
 static bool inline_jit_compile(inline_node *iln)
 {
        bool                r;
        methodinfo         *m;
        jitdata            *jd;
-       s4 i;
+
+       /* XXX should share code with jit.c */
 
        assert(iln);
        m = iln->m;
@@ -233,44 +244,29 @@ static bool inline_jit_compile(inline_node *iln)
 
 #if defined(ENABLE_THREADS)
        /* enter a monitor on the method */
-       builtin_monitorenter((java_objectheader *) m);
+       lock_monitor_enter((java_objectheader *) m);
 #endif
-       
-       /* XXX dont parse these a second time because parse is not idempotent */
-       for (i=0; i<m->jcodelength; ++i) {
-               if (m->jcode[i] == JAVA_TABLESWITCH || m->jcode[i] == JAVA_LOOKUPSWITCH) {
-                       r = false;
-                       goto return_r;
-               }
-       }
 
        /* allocate jitdata structure and fill it */
 
-       jd = DNEW(jitdata);
+       jd = jit_jitdata_new(m);
+       iln->jd = jd;
 
-       jd->m     = m;
-       jd->cd    = DNEW(codegendata);
-       jd->rd    = DNEW(registerdata);
-#if defined(ENABLE_LOOP)
-       jd->ld    = DNEW(loopdata);
-#endif
-       jd->flags = 0;
-
-       /* Allocate codeinfo memory from the heap as we need to keep them. */
+       jd->flags = 0; /* XXX */
 
-       jd->code  = code_codeinfo_new(m); /* XXX check allocation */
+       /* initialize the register allocator */
 
-#if defined(ENABLE_JIT)
-# if defined(ENABLE_INTRP)
-       if (!opt_intrp)
-# endif
-               /* initialize the register allocator */
-               reg_setup(jd);
-#endif
+       reg_setup(jd);
 
        /* setup the codegendata memory */
 
-       codegen_setup(jd);
+       /* XXX do a pseudo setup */
+       jd->cd = DNEW(codegendata);
+       MZERO(jd->cd, codegendata, 1);
+       jd->cd->maxstack = m->maxstack;
+       jd->cd->maxlocals = m->maxlocals;
+       jd->cd->method = m;
+       /* XXX uses too much dump memory codegen_setup(jd); */
 
        /* now call internal compile function */
 
@@ -283,7 +279,6 @@ static bool inline_jit_compile(inline_node *iln)
        /* free some memory */
 #if 0
 
-       
 #if defined(ENABLE_JIT)
 # if defined(ENABLE_INTRP)
        if (!opt_intrp)
@@ -293,20 +288,18 @@ static bool inline_jit_compile(inline_node *iln)
 
 #endif
 
-return_r:
 #if defined(ENABLE_THREADS)
        /* leave the monitor */
-       builtin_monitorexit((java_objectheader *) m );
-#endif
-
-#if 0
-       show_method(jd);
+       lock_monitor_exit((java_objectheader *) m );
 #endif
 
        return r;
 }
 
-static void insert_inline_node(inline_node *parent,inline_node *child)
+
+/* inlining tree handling *****************************************************/
+
+static void insert_inline_node(inline_node *parent, inline_node *child)
 {
        inline_node *first;
        inline_node *succ;
@@ -315,6 +308,8 @@ static void insert_inline_node(inline_node *parent,inline_node *child)
 
        child->parent = parent;
 
+       child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
+
        first = parent->children;
        if (!first) {
                /* insert as only node */
@@ -326,6 +321,8 @@ static void insert_inline_node(inline_node *parent,inline_node *child)
 
        /* {there is at least one child already there} */
 
+       /* XXX is this search necessary, or could we always add at the end? */
+
        succ = first;
        while (succ->callerpc < child->callerpc) {
                succ = succ->next;
@@ -340,7 +337,7 @@ static void insert_inline_node(inline_node *parent,inline_node *child)
        }
 
        assert(succ->callerpc > child->callerpc);
-       
+
        /* insert before succ */
 
        child->prev = succ->prev;
@@ -349,320 +346,192 @@ static void insert_inline_node(inline_node *parent,inline_node *child)
        child->next->prev = child;
 }
 
-static stackptr relocate_stack_ptr_intern(inline_node *iln,stackptr o_link,ptrint curreloc)
+
+/* variable handling **********************************************************/
+
+static s4 inline_new_variable(jitdata *jd, s4 type, s4 flags)
 {
-       inline_stack_translation *tr;
-       
-       if (o_link) {
-               /* XXX should limit range in both directions */
-               if (o_link < iln->ctx->o_translationlimit) {
-                       /* this stack slot is from an earlier chunk, we must look it up */
-                       tr = iln->ctx->stacktranslationstart;
-                       while (tr >= iln->ctx->stacktranslation) {
-                               if (o_link == tr->o_sp) {
-                                       DOLOG(printf("\t\t\ttable lookup %p -> %d\n",(void*)o_link,DEBUG_SLOT(tr->n_sp)));
-                                       return tr->n_sp;
-                               }
-                               tr--;
-                       }
-                       DOLOG(debug_dump_inline_context(iln));
-                       DOLOG(printf("\t\tFAILED TO TRANSLATE: %p\n",(void*)o_link));
-                       assert(false);
-               }
-               else {
-                       /* this stack slot it in the most recent chunk */
-                       assert(curreloc);
-                       DOLOG( printf("\t\t\toffset %d\n",(int)curreloc) );
-                       return (stackptr) ((u1*)o_link + curreloc);
-               }
+       s4 index;
+       s4 newcount;
+
+       index = jd->vartop++;
+       if (index >= jd->varcount) {
+               newcount = jd->vartop * 2; /* XXX */
+               jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, newcount);
+               MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
+               jd->varcount = newcount;
        }
-       return iln->n_callerstack;
-}
 
-/* XXX for debugging */
-static stackptr relocate_stack_ptr(inline_node *iln,stackptr o_link,ptrint curreloc)
-{
-       stackptr new;
-
-       new = relocate_stack_ptr_intern(iln,o_link,curreloc);
-       DOLOG(
-               printf("\t\treloc %p -> %d (%p)\t(translimit=%p)\n",
-                               (void*)o_link,DEBUG_SLOT(new),(void*)new,(void*)iln->ctx->o_translationlimit)
-       );
-       return new;
-}
+       jd->var[index].type = type;
+       jd->var[index].flags = flags;
 
-static void emit_instruction(inline_node *iln,instruction *ins,ptrint curreloc,stackptr o_curstack)
-{
-       char indent[100];
-       int i;
-       instruction *n_ins;
-       inline_target_ref *ref;
+       return index;
+}
 
-       assert(iln && ins);
 
-       for (i=0; i<iln->depth; ++i)
-               indent[i] = '\t';
-       indent[i] = 0;
+static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
+{
+       varinfo *v;
+       s4       newidx;
 
-       n_ins = (iln->inlined_iinstr_cursor++);
-       assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
-       
-       *n_ins = *ins;
+       v = &(origjd->var[origidx]);
 
-       switch (n_ins[0].opc) {
-                               /****************************************/
-                               /* VARIABLE ACCESS                      */
-
-                       case ICMD_ILOAD:
-                       case ICMD_IINC:
-                       case ICMD_FLOAD:
-                       case ICMD_LLOAD:
-                       case ICMD_DLOAD:
-                       case ICMD_ISTORE:
-                       case ICMD_FSTORE:
-                       case ICMD_LSTORE:
-                       case ICMD_DSTORE:
-                       case ICMD_ALOAD:
-                       case ICMD_ASTORE:
-                   case ICMD_RET:
-                       n_ins[0].op1 += iln->localsoffset;
-                       break;
+       newidx = inline_new_variable(jd, v->type, v->flags);
 
-                       case ICMD_GOTO:
-                       case ICMD_IFNULL:
-                       case ICMD_IFNONNULL:
-                       case ICMD_IFEQ:
-                       case ICMD_IFNE:
-                       case ICMD_IFLT:
-                       case ICMD_IFGE:
-                       case ICMD_IFGT:
-                       case ICMD_IFLE:
-                       case ICMD_IF_ICMPEQ:
-                       case ICMD_IF_ICMPNE:
-                       case ICMD_IF_ICMPLT:
-                       case ICMD_IF_ICMPGE:
-                       case ICMD_IF_ICMPGT:
-                       case ICMD_IF_ICMPLE:
-                       case ICMD_IF_ACMPEQ:
-                       case ICMD_IF_ACMPNE:
-                       case ICMD_IF_LEQ:
-                       case ICMD_IF_LNE:
-                       case ICMD_IF_LLT:
-                       case ICMD_IF_LGE:
-                       case ICMD_IF_LGT:
-                       case ICMD_IF_LLE:
-                       case ICMD_IF_LCMPEQ:
-                       case ICMD_IF_LCMPNE:
-                       case ICMD_IF_LCMPLT:
-                       case ICMD_IF_LCMPGE:
-                       case ICMD_IF_LCMPGT:
-                       case ICMD_IF_LCMPLE:
-                       case ICMD_JSR:
-                               ref = DNEW(inline_target_ref);
-                               ref->ref = (basicblock **) &(n_ins[0].target);
-                               ref->next = iln->refs;
-                               iln->refs = ref;
-                               break;
+       jd->var[newidx].vv = v->vv;
 
-                               /****************************************/
-                               /* RETURNS                              */
+       return newidx;
+}
 
-                       case ICMD_RETURN:
-                               if (iln->parent) {
-                                       n_ins[0].opc = ICMD_GOTO;
-                                       n_ins[0].dst = NULL;
-                                       goto return_tail;
-                               }
-                               break;
-
-                       case ICMD_ARETURN:
-                       case ICMD_IRETURN:
-                       case ICMD_LRETURN:
-                       case ICMD_FRETURN:
-                       case ICMD_DRETURN:
-                       if (iln->parent) {
-                               n_ins[0].opc = ICMD_INLINE_GOTO;
-                               n_ins[0].dst = o_curstack;
-return_tail:
-                               n_ins[0].target = (void *) (ptrint) (iln->depth + 0x333); /* XXX */
-                               ref = DNEW(inline_target_ref);
-                               ref->ref = (basicblock **) &(n_ins[0].target);
-                               ref->next = iln->refs;
-                               iln->refs = ref;
-                       }
-                       break;
-       }
 
-       n_ins[0].dst = relocate_stack_ptr(iln,n_ins[0].dst,curreloc);
+static s4 inline_new_temp_variable(jitdata *jd, s4 type)
+{
+       return inline_new_variable(jd, type, 0);
 }
 
-static stackptr inline_new_stackslot(inline_node *iln,stackptr n_curstack,s4 type)
+
+static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
 {
-       stackptr n_sp;
-
-       n_sp = iln->n_inlined_stack_cursor++;
-       assert((n_sp - iln->n_inlined_stack) < iln->cumul_stackcount);
-
-       n_sp->prev = n_curstack;
-       n_sp->type = type;
-       n_sp->varkind = TEMPVAR;
-       n_sp->varnum = stack_depth(n_curstack); /* XXX inefficient */
-       n_sp->flags = 0;
-#ifndef NDEBUG
-       n_sp->regoff = (IS_FLT_DBL_TYPE(type)) ? -1 : INT_ARG_CNT;
-#endif
+       s4 idx;
 
-       return n_sp;
+       idx = varmap[index];
+
+       if (idx < 0) {
+               idx = inline_new_variable_clone(jd, origjd, index);
+               varmap[index] = idx;
+       }
+
+       return idx;
 }
 
-static stackptr emit_inlining_prolog(inline_node *iln,inline_node *callee,stackptr n_curstack,instruction *o_iptr)
+
+static s4 *create_variable_map(inline_node *callee)
 {
-       methodinfo *calleem;
-       methoddesc *md;
-       int i;
-       int localindex;
-       int depth;
-       int type;
-       bool isstatic;
-       instruction *n_ins;
-       insinfo_inline *insinfo;
+       s4 *varmap;
+       s4 i, t;
+       s4 idx;
+       s4 n_idx;
+       s4 avail;
+       varinfo *v;
+       varinfo vinfo;
 
-       assert(iln && callee && o_iptr);
+       /* create the variable mapping */
 
-       calleem = callee->m;
-       md = calleem->parseddesc;
-       isstatic = (calleem->flags & ACC_STATIC);
+       varmap = DMNEW(s4, callee->jd->varcount);
+       for (i=0; i<callee->jd->varcount; ++i)
+               varmap[i] = -1;
 
-       localindex = callee->localsoffset + md->paramslots;
-       depth = stack_depth(n_curstack) - 1; /* XXX inefficient */
-       for (i=md->paramcount-1; i>=0; --i) {
-               assert(iln);
+       /* translate local variables */
 
-               n_ins = (iln->inlined_iinstr_cursor++);
-               assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
+       for (i=0; i<callee->m->maxlocals; ++i) {
+               for (t=0; t<5; ++t) {
+                       idx = callee->jd->local_map[5*i + t];
+                       if (idx == UNUSED)
+                               continue;
 
-               type = md->paramtypes[i].type;
+                       v = &(callee->jd->var[idx]);
+                       assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
+                       v->type = t; /* XXX restore if it is TYPE_VOID */
 
-               localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
-               assert(callee->regdata);
+                       avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
 
-               DOLOG( printf("prologlocal %d type=%d lofs=%d in ",
-                          localindex - callee->localsoffset,
-                          callee->regdata->locals[localindex - callee->localsoffset][type].type,callee->localsoffset);
-                               method_println(callee->m); );
+                       if (avail == UNUSED) {
+                               avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, idx);
+                               callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
+                       }
 
-               if ((callee->regdata->locals[localindex - callee->localsoffset][type].type >= 0)
-                               ||
-                       (i==0 && callee->synchronize && !isstatic)) 
-               {
-                       n_ins->opc = ICMD_ISTORE + type;
-                       n_ins->op1 = localindex;
-               }
-               else {
-                       n_ins->opc = IS_2_WORD_TYPE(type) ? ICMD_POP2 : ICMD_POP; /* XXX is POP2 correct? */
+                       varmap[idx] = avail;
                }
-               n_ins->line = o_iptr->line;
-               assert(n_curstack);
-               if (n_curstack->varkind == ARGVAR) {
-                       n_curstack->varkind = TEMPVAR;
-                       n_curstack->varnum = depth;
-                       n_curstack->flags &= ~INMEMORY;
+       }
+
+       /* for synchronized instance methods we need an extra local */
+
+       if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
+               n_idx = callee->localsoffset - 1;
+               assert(n_idx >= 0);
+               assert(callee->parent);
+               assert(n_idx == callee->parent->localsoffset + callee->parent->m->maxlocals);
+
+               avail = callee->ctx->resultjd->local_map[5*n_idx + TYPE_ADR];
+
+               if (avail == UNUSED) {
+                       avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
+                       callee->ctx->resultjd->local_map[5*n_idx + TYPE_ADR] = avail;
                }
-               n_curstack = n_curstack->prev;
-               n_ins->dst = n_curstack;
-               depth--;
+
+               callee->synclocal = avail;
+       }
+       else {
+               callee->synclocal = UNUSED;
        }
 
-       /* INLINE_START instruction */
+       return varmap;
+}
 
-       n_ins = (iln->inlined_iinstr_cursor++);
-       assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
 
-       insinfo = DNEW(insinfo_inline);
-       insinfo->method = callee->m;
-       insinfo->outer = iln->m;
-       /* XXX using local 0 only works if it is read-only!! */
-       insinfo->synclocal = callee->localsoffset;
-       insinfo->synchronize = callee->synchronize;
+/* basic block translation ****************************************************/
 
-       n_ins->opc = ICMD_INLINE_START;
-       n_ins->dst = n_curstack;
-       n_ins->target = insinfo;
-       n_ins->line = o_iptr->line;
-       iln->inline_start_instruction = n_ins;
+#define INLINE_RETURN_REFERENCE(callee)  \
+       ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
+
+
+static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
+{
+       inline_target_ref *ref;
 
-       return n_curstack;
+       ref = DNEW(inline_target_ref);
+       ref->ref = blockp;
+       ref->next = iln->refs;
+       iln->refs = ref;
 }
 
-static void emit_inlining_epilog(inline_node *iln,inline_node *callee,stackptr n_curstack,instruction *o_iptr)
+
+static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
 {
-       instruction *n_ins;
-       
-       assert(iln && callee && o_iptr);
-       assert(iln->inline_start_instruction);
+       inline_context *ctx;
 
-       n_ins = (iln->inlined_iinstr_cursor++);
-       assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
+       ctx = iln->ctx;
+       assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
 
-       n_ins->opc = ICMD_INLINE_END;
-       n_ins->dst = n_curstack;
-       n_ins->target = iln->inline_start_instruction->target; /* insinfo_inline * */
-       n_ins->line = o_iptr->line;
+       ctx->blockmap[ctx->blockmap_index].iln = iln;
+       ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
+       ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
+
+       ctx->blockmap_index++;
 }
 
-static void rewrite_stack(inline_node *iln,stackptr o_first,stackptr o_last,ptrint curreloc)
+
+static basicblock * inline_map_block(inline_node *iln,
+                                                                        basicblock *o_block,
+                                                                        inline_node *targetiln)
 {
-       int n;
-       stackptr o_sp;
-       stackptr n_sp;
-       
+       inline_block_map *bm;
+       inline_block_map *bmend;
+
        assert(iln);
+       assert(targetiln);
 
-       if (!o_first) {
-               assert(!o_last);
-               DOLOG(printf("rewrite_stack: no stack slots\n"));
-               return;
-       }
+       if (!o_block)
+               return NULL;
 
-       assert(o_first);
-       assert(o_last);
-       assert(o_first <= o_last);
-
-       n = o_last - o_first + 1;
-       assert(n >= 0);
-
-       o_sp = o_first;
-       n_sp = iln->n_inlined_stack_cursor;
-       
-       DOLOG(
-       printf("rewrite_stack: rewriting %d stack slots (%p,%p) -> (%d,%d)\n",
-                       n,(void*)o_first,(void*)o_last,DEBUG_SLOT(n_sp),
-                       DEBUG_SLOT(n_sp+n-1))
-       );
-
-       DOLOG( printf("o_first = "); debug_dump_stack(o_first); printf("\n") );
-       DOLOG( printf("o_last = "); debug_dump_stack(o_last); printf("\n") );
-       
-       while (o_sp <= o_last) {
-               *n_sp = *o_sp;
-
-               n_sp->prev = relocate_stack_ptr(iln,n_sp->prev,curreloc);
-               switch (n_sp->varkind) {
-                       case STACKVAR: n_sp->varnum += iln->n_callerstackdepth; break;
-                       case LOCALVAR: n_sp->varnum += iln->localsoffset; break;
-               }
-               
-               o_sp++;
-               n_sp++;
+       bm = iln->ctx->blockmap;
+       bmend = bm + iln->ctx->blockmap_index;
+
+       while (bm < bmend) {
+               assert(bm->iln && bm->o_block && bm->n_block);
+               if (bm->o_block == o_block && bm->iln == targetiln)
+                       return bm->n_block;
+               bm++;
        }
-       DOLOG( printf("n_sp = "); debug_dump_stack(n_sp-1); printf("\n") );
-       
-       iln->n_inlined_stack_cursor = n_sp;
-       assert((n_sp - iln->n_inlined_stack) <= iln->cumul_stackcount);
+
+       assert(false);
+       return NULL; /* not reached */
 }
 
-static void inline_resolve_block_refs(inline_target_ref **refs,basicblock *o_bptr,basicblock *n_bptr)
+
+static void inline_resolve_block_refs(inline_target_ref **refs,
+                                                                         basicblock *o_bptr,
+                                                                         basicblock *n_bptr)
 {
        inline_target_ref *ref;
        inline_target_ref *prev;
@@ -671,17 +540,20 @@ static void inline_resolve_block_refs(inline_target_ref **refs,basicblock *o_bpt
        prev = NULL;
        while (ref) {
                if (*(ref->ref) == o_bptr) {
-                       DOLOG(
+
+#if defined(INLINE_VERBOSE)
+                       if (inline_debug_log) {
                                if ((ptrint) o_bptr < (0x333+100)) { /* XXX */
                                        printf("resolving RETURN block reference %p -> new L%03d (%p)\n",
-                                                       (void*)o_bptr,n_bptr->debug_nr,(void*)n_bptr);
+                                                       (void*)o_bptr, n_bptr->nr, (void*)n_bptr);
                                }
                                else {
                                        printf("resolving block reference old L%03d (%p) -> new L%03d (%p)\n",
-                                                       o_bptr->debug_nr,(void*)o_bptr,n_bptr->debug_nr,(void*)n_bptr);
+                                                       o_bptr->nr, (void*)o_bptr, n_bptr->nr, (void*)n_bptr);
                                }
-                       );
-                       
+                       }
+#endif
+
                        *(ref->ref) = n_bptr;
                        if (prev) {
                                prev->next = ref->next;
@@ -697,658 +569,1520 @@ static void inline_resolve_block_refs(inline_target_ref **refs,basicblock *o_bpt
        }
 }
 
-static basicblock * create_block(inline_node *iln,basicblock *o_bptr,inline_target_ref **refs,int indepth)
-{
-       basicblock *n_bptr;
-       stackptr n_sp;
-       int i;
-       s4 temp;
 
+/* basic block creation *******************************************************/
+
+static basicblock * create_block(inline_node *container,
+                                                                inline_node *iln,
+                                                                inline_node *inner,
+                                                                basicblock *o_bptr,
+                                                                inline_target_ref **refs,
+                                                                int indepth)
+{
+       basicblock  *n_bptr;
+       inline_node *outer;
+       s4           i;
+       s4           depth;
+       s4           varidx;
+       s4           newvaridx;
+
+       assert(container);
        assert(iln);
-       
-       n_bptr = iln->inlined_basicblocks_cursor++;
+       assert(inner);
+       assert(indepth >= 0);
+
+       n_bptr = container->inlined_basicblocks_cursor++;
        assert(n_bptr);
-       assert((n_bptr - iln->inlined_basicblocks) < iln->cumul_basicblockcount);
-       
-       /* XXX hack */
-       BASICBLOCK_INIT(n_bptr,iln->m);
-       n_bptr->nr = -1;
-       
-       n_bptr->iinstr = iln->inlined_iinstr_cursor;
-       n_bptr->next = n_bptr+1;
-       n_bptr->debug_nr = iln->ctx->next_block_number++;
+       assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
+
+       BASICBLOCK_INIT(n_bptr, iln->m);
+
+       n_bptr->iinstr = container->inlined_iinstr_cursor;
+       n_bptr->next = n_bptr + 1;
+       n_bptr->nr = container->ctx->next_block_number++;
        n_bptr->indepth = indepth;
+       n_bptr->flags = BBFINISHED; /* XXX */
+
+       if (indepth > container->ctx->maxinoutdepth)
+               container->ctx->maxinoutdepth = indepth;
 
        if (indepth) {
-               /* allocate stackslots */
-               iln->n_inlined_stack_cursor += indepth;
-               n_sp = iln->n_inlined_stack_cursor - 1;
-               n_bptr->instack = n_sp;
-
-               assert((n_sp - iln->n_inlined_stack) < iln->cumul_stackcount);
-
-               /* link the stack elements */
-               for (i=indepth-1; i>=0; --i) {
-                       n_sp->varkind = STACKVAR;
-                       n_sp->varnum = i;
-                       n_sp->prev = (i) ? n_sp-1 : NULL;
-                       n_sp->flags = 0; /* XXX */
-                       n_sp--;
+               n_bptr->invars = DMNEW(s4, indepth);
+
+
+               for (i=0; i<indepth; ++i)
+                       n_bptr->invars[i] = -1; /* XXX debug */
+
+               /* pass-through variables enter the block */
+
+               outer = inner->parent;
+               while (outer != NULL) {
+                       depth = outer->n_passthroughcount;
+
+                       assert(depth + inner->n_selfpassthroughcount <= indepth);
+
+                       for (i=0; i<inner->n_selfpassthroughcount; ++i) {
+                               varidx = inner->n_passthroughvars[i];
+                               newvaridx =
+                                       inline_new_variable_clone(container->ctx->resultjd,
+                                                                                         outer->jd,
+                                                                                         varidx);
+                               n_bptr->invars[depth + i] = newvaridx;
+                               outer->varmap[varidx] = newvaridx;
+                       }
+                       inner = outer;
+                       outer = outer->parent;
                }
        }
+       else {
+               n_bptr->invars = NULL;
+       }
 
+       /* XXX move this to callers with o_bptr != NULL? */
        if (o_bptr) {
                assert(refs);
-               inline_resolve_block_refs(refs,o_bptr,n_bptr);
+               inline_resolve_block_refs(refs, o_bptr, n_bptr);
        }
-       
+
+       {
+               varinfo *dv;
+
+               /* XXX for the verifier. should not be here */
+
+               dv = DMNEW(varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
+               MZERO(dv, varinfo,  iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
+               n_bptr->inlocals = dv;
+       }
+
        return n_bptr;
 }
 
-static void fill_translation_table(inline_node *iln,stackptr o_sp,stackptr n_sp,int n_depth)
+
+static basicblock * create_body_block(inline_node *iln,
+                                                                         basicblock *o_bptr, s4 *varmap)
 {
-       int i;
+       basicblock *n_bptr;
+       s4 i;
 
-       DOLOG(
-       printf("fill_translation_table (newdepth=%d):\n",n_depth);
-       printf("\tos_sp = "); debug_dump_stack(o_sp); printf("\n");
-       printf("\tns_sp = "); debug_dump_stack(n_sp); printf("\n");
-       );
-
-       /* we must translate all stack slots that were present before the call XXX  */
-       /* and the instack of the block */
-       iln->ctx->stacktranslationstart = iln->ctx->stacktranslation + (n_depth - 1);
-
-       /* fill the translation table */
-       if (n_depth) {
-               i = n_depth-1;
-
-               while (o_sp) {
-                       assert(i >= 0);
-                       assert(n_sp);
-                       iln->ctx->stacktranslation[i].o_sp = o_sp;
-                       iln->ctx->stacktranslation[i].n_sp = n_sp;
-                       n_sp->flags |= (o_sp->flags & SAVEDVAR); /* XXX correct? */
-                       n_sp->type = o_sp->type; /* XXX we overwrite this anyway with STACKVAR, right? */
-                       o_sp = o_sp->prev;
-                       n_sp = n_sp->prev;
-                       i--;
-               }
+       n_bptr = create_block(iln, iln, iln, o_bptr, &(iln->refs),
+                                                 o_bptr->indepth + iln->n_passthroughcount);
 
-               while (n_sp) {
-                       assert(i >= 0);
-                       assert(iln->ctx->stacktranslation[i].o_sp);
-                       iln->ctx->stacktranslation[i].n_sp = n_sp;
-                       n_sp->flags |= SAVEDVAR; /* XXX this is too conservative */
-                       n_sp = n_sp->prev;
-                       i--;
-               }
+       n_bptr->type = o_bptr->type;
+       n_bptr->flags = o_bptr->flags;
 
-               assert(i == -1);
+       /* translate the invars of the original block */
+
+       for (i=0; i<o_bptr->indepth; ++i) {
+               n_bptr->invars[iln->n_passthroughcount + i] =
+                       inline_translate_variable(iln->ctx->resultjd, iln->jd,
+                               varmap,
+                               o_bptr->invars[i]);
        }
+
+       return n_bptr;
 }
 
-static void rewrite_method(inline_node *iln)
+
+static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
 {
-       basicblock *o_bptr;
-       s4 len;
-       instruction *o_iptr;
-       instruction *n_iptr;
-       stackptr o_dst;
-       stackptr n_sp;
-       stackptr o_sp;
-       stackptr o_curstack;
-       stackptr o_nexttorewrite;
-       stackptr o_lasttorewrite;
-       inline_node *nextcall;
-       ptrint curreloc;
        basicblock *n_bptr;
-       inline_block_map *bm;
-       int i;
-       int icount;
+       s4 retcount;
+       s4 idx;
+       varinfo vinfo;
 
-       assert(iln);
+       /* number of return variables */
 
-       n_bptr = NULL;
-       nextcall = iln->children;
+       retcount = (callee->n_resultlocal == -1
+                               && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
 
-       /* set memory cursors */
-       iln->inlined_iinstr_cursor = iln->inlined_iinstr;
-       iln->n_inlined_stack_cursor = iln->n_inlined_stack;
-       iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
+       /* start the epilog block */
 
-       /* loop over basic blocks */
-       o_bptr = iln->m->basicblocks;
-       for (; o_bptr; o_bptr = o_bptr->next) {
+       n_bptr = create_block(caller, caller, callee, INLINE_RETURN_REFERENCE(callee),
+                       &(callee->refs), callee->n_passthroughcount + retcount);
 
-               if (o_bptr->flags < BBREACHED) {
-                       DOLOG(
-                       printf("skipping old L%03d (flags=%d,type=%d,os=%p,oid=%d,ois=%p,cursor=%d,callerstack=%d) of ",
-                                       o_bptr->debug_nr,o_bptr->flags,o_bptr->type,
-                                       (void*)o_bptr->stack,o_bptr->indepth,(void*)o_bptr->instack,
-                                       DEBUG_SLOT(iln->n_inlined_stack_cursor),
-                                       DEBUG_SLOT(iln->n_callerstack));
-                       method_println(iln->m);
-                       );
+       /* return variable */
 
-                       n_bptr = create_block(iln,o_bptr,&(iln->refs),o_bptr->indepth + iln->n_callerstackdepth);
-                       n_bptr->type = o_bptr->type;
-                       /* enter it in the blockmap */
-                       iln->ctx->blockmap[iln->ctx->blockmap_index].iln = iln;
-                       iln->ctx->blockmap[iln->ctx->blockmap_index].o_block = o_bptr;
-                       iln->ctx->blockmap[iln->ctx->blockmap_index++].n_block = n_bptr;
-                       n_bptr->flags = o_bptr->flags;
-                       continue;
-               }
+       if (retcount) {
+               idx = inline_new_variable(caller->ctx->resultjd,
+                          callee->m->parseddesc->returntype.type, 0 /* XXX */);
+               n_bptr->invars[callee->n_passthroughcount] = idx;
+               varmap[callee->callerins->dst.varindex] = idx;
+       }
 
-               assert(o_bptr->stack);
-               
-               len = o_bptr->icount;
-               o_iptr = o_bptr->iinstr;
+       n_bptr->flags = /* XXX original block flags */ BBFINISHED;
+       n_bptr->type = BBTYPE_STD;
 
-               DOLOG(
-               printf("rewriting old L%03d (flags=%d,type=%d,os=%p,oid=%d,ois=%p,cursor=%d,callerstack=%d) of ",
-                               o_bptr->debug_nr,o_bptr->flags,o_bptr->type,
-                               (void*)o_bptr->stack,o_bptr->indepth,(void*)o_bptr->instack,
-                               DEBUG_SLOT(iln->n_inlined_stack_cursor),
-                               DEBUG_SLOT(iln->n_callerstack));
-               method_println(iln->m);
-               printf("o_instack: ");debug_dump_stack(o_bptr->instack);printf("\n");
-               printf("o_callerstack: ");debug_dump_stack(iln->o_callerstack);printf("\n");
-               );
+       return n_bptr;
+}
 
-               o_curstack = o_bptr->instack;
 
-               /* create an inlined clone of this block */
-               n_bptr = create_block(iln,o_bptr,&(iln->refs),o_bptr->indepth + iln->n_callerstackdepth);
-               n_bptr->type = o_bptr->type;
-               n_bptr->flags = o_bptr->flags;
+static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
+{
+       inline_node *outer;
+       s4           i;
+       s4           depth;
+       s4           varidx;
 
-               /* enter it in the blockmap */
-               iln->ctx->blockmap[iln->ctx->blockmap_index].iln = iln;
-               iln->ctx->blockmap[iln->ctx->blockmap_index].o_block = o_bptr;
-               iln->ctx->blockmap[iln->ctx->blockmap_index++].n_block = n_bptr;
+       n_bptr->outdepth = outdepth;
+       n_bptr->outvars = DMNEW(s4, outdepth);
 
-               DOLOG( debug_dump_inline_context(iln) );
+       for (i=0; i<outdepth; ++i)
+               n_bptr->outvars[i] = 0; /* XXX debug */
 
-               if (iln->n_callerstackdepth)
-                       iln->n_callerstack = n_bptr->instack-o_bptr->indepth;
-               else
-                       iln->n_callerstack = NULL;
-               fill_translation_table(iln,iln->o_callerstack,iln->n_callerstack,iln->n_callerstackdepth);
-               fill_translation_table(iln,o_bptr->instack,n_bptr->instack,n_bptr->indepth);
-               iln->ctx->o_translationlimit = o_bptr->stack;
+       if (outdepth > iln->ctx->maxinoutdepth)
+               iln->ctx->maxinoutdepth = outdepth;
 
-               DOLOG( debug_dump_inline_context(iln) );
+       /* pass-through variables leave the block */
 
-               /* calculate the stack element relocation */
-               curreloc = (u1*)iln->n_inlined_stack_cursor - (u1*)o_bptr->stack;
-               DOLOG( printf("curreloc <- %d = %p - %p\n",(int)curreloc,(void*)iln->n_inlined_stack_cursor,(void*)(u1*)o_bptr->stack) );
+       outer = inner->parent;
+       while (outer != NULL) {
+               depth = outer->n_passthroughcount;
 
-               o_nexttorewrite = o_bptr->stack;
-               o_lasttorewrite = o_bptr->stack-1;
-               assert(o_nexttorewrite);
-                       
-               icount = 0;
+               assert(depth + inner->n_selfpassthroughcount <= outdepth);
 
-               while (--len >= 0) {
-                       o_dst = o_iptr->dst;
+               for (i=0; i<inner->n_selfpassthroughcount; ++i) {
+                       varidx = inner->n_passthroughvars[i];
+                       n_bptr->outvars[depth + i] =
+                               inline_translate_variable(iln->ctx->resultjd,
+                                                                                 outer->jd,
+                                                                                 outer->varmap,
+                                                                                 varidx);
+               }
+               inner = outer;
+               outer = outer->parent;
+       }
+}
 
-                       DOLOG( printf("o_curstack = "); debug_dump_stack(o_curstack); show_icmd(o_iptr,false); printf(", dst = "); debug_dump_stack(o_dst); printf("\n") );
 
-                       if (nextcall && o_iptr == nextcall->callerins) {
+static void close_prolog_block(inline_node *iln,
+                                                          basicblock *n_bptr,
+                                                          inline_node *nextcall)
+{
+       /* XXX add original outvars! */
+       close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
 
-                               /* rewrite stack elements produced so far in this block */
-                               if (o_nexttorewrite <= o_lasttorewrite) {
-                                       rewrite_stack(iln, o_nexttorewrite, o_lasttorewrite, curreloc);
-                               }
-                               
-                               /* write the inlining prolog */
-                               n_sp = emit_inlining_prolog(iln,nextcall,relocate_stack_ptr(iln,o_curstack,curreloc),o_iptr);
-                               icount += nextcall->m->parseddesc->paramcount + 1; /* XXX prolog instructions */
-
-                               /* find the first stack slot under the arguments of the invocation */
-                               o_sp = o_curstack;
-                               for (i=0; i < nextcall->m->parseddesc->paramcount; ++i) {
-                                       assert(o_sp);
-                                       o_sp = o_sp->prev;
-                               }
-                               nextcall->o_callerstack = o_sp;
+       /* pass-through variables */
 
-                               /* see how deep the new stack is after the arguments have been removed */
-                               i = stack_depth(n_sp);
-                               assert(i == stack_depth(nextcall->o_callerstack) + iln->n_callerstackdepth);
+       DOLOG( printf("closed prolog block:\n");
+                  show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
+}
 
-                               /* end current block */
-                               n_bptr->icount = icount;
-                               n_bptr->outstack = n_sp;
-                               n_bptr->outdepth = i;
-                               
-                               /* caller stack depth for the callee */
-                               assert(nextcall->n_callerstackdepth == i);
-                               
-                               /* set memory pointers in the callee */
-                               nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
-                               nextcall->n_inlined_stack = iln->n_inlined_stack_cursor;
-                               nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
-                               
-                               /* recurse */
-                               DOLOG( printf("entering inline "); show_icmd(o_iptr,false); printf("\n") );
-                               rewrite_method(nextcall);
-                               DOLOG( printf("leaving inline "); show_icmd(o_iptr,false); printf("\n") );
 
-                               /* skip stack slots used by the inlined callee */
-                               curreloc += (u1*)nextcall->n_inlined_stack_cursor - (u1*)iln->n_inlined_stack_cursor;
-                               
-                               /* update memory cursors */
-                               assert(nextcall->inlined_iinstr_cursor == iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
-                               /* XXX m->stackcount seems to be a conservative estimate */
-                               assert(nextcall->n_inlined_stack_cursor <= iln->n_inlined_stack_cursor + nextcall->cumul_stackcount);
-                               assert(nextcall->inlined_basicblocks_cursor == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
-                               iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
-                               iln->n_inlined_stack_cursor = nextcall->n_inlined_stack_cursor;
-                               iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
+static void close_body_block(inline_node *iln,
+                                                        basicblock *n_bptr,
+                                                        basicblock *o_bptr,
+                                                        s4 *varmap,
+                                                        s4 retcount,
+                                                        s4 retidx)
+{
+       s4 i;
 
-                               /* start new block */
-                               i = (nextcall->m->parseddesc->returntype.type == TYPE_VOID) ? 0 : 1; /* number of return slots */
-                               assert(i == 0 || i == 1);
-                               n_bptr = create_block(iln,(void*) (ptrint) (nextcall->depth + 0x333) /*XXX*/,
-                                               &(nextcall->refs),nextcall->n_callerstackdepth + i);
-                               n_bptr->flags = o_bptr->flags;
-                               icount = 0;
-
-                               /* skip allocated stack slots */
-                               curreloc += sizeof(stackelement) * (n_bptr->indepth - i);
-                               
-                               /* fill the translation table for the slots present before the call */
-                               n_sp = n_bptr->instack;
-                               fill_translation_table(iln,nextcall->o_callerstack,(i) ? n_sp->prev : n_sp,nextcall->n_callerstackdepth);
-
-                               /* the return slot */
-                               if (i) {
-                                       assert(o_dst);
-                                       assert(n_sp);
-                                       fill_translation_table(iln,o_dst,n_sp,nextcall->n_callerstackdepth + 1);
-
-                                       o_nexttorewrite = o_dst + 1;
-                                       o_lasttorewrite = o_dst;
-                               }
-                               else {
-                                       /* the next chunk of stack slots start with (including) the slots produced */
-                                       /* by the invocation */
-                                       o_nexttorewrite = o_lasttorewrite + 1;
-                                       o_lasttorewrite = o_nexttorewrite - 1;
+       close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
+
+       /* translate the outvars of the original block */
+
+       /* XXX reuse code */
+       for (i=0; i<o_bptr->outdepth; ++i) {
+               n_bptr->outvars[iln->n_passthroughcount + i] =
+                       inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
+                                       o_bptr->outvars[i]);
+       }
+
+       /* set the return variable, if any */
+
+       if (retcount) {
+               assert(retidx >= 0);
+               n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
+       }
+}
+
+
+/* inlined code generation ****************************************************/
+
+static s4 emit_inlining_prolog(inline_node *iln,
+                                                          inline_node *callee,
+                                                          instruction *o_iptr,
+                                                          s4 *varmap)
+{
+       methodinfo *calleem;
+       methoddesc *md;
+       int i;
+       int localindex;
+       int type;
+       bool isstatic;
+       instruction *n_ins;
+       insinfo_inline *insinfo;
+       s4 argvar;
+
+       assert(iln && callee && o_iptr);
+
+       calleem = callee->m;
+       md = calleem->parseddesc;
+       isstatic = (calleem->flags & ACC_STATIC);
+
+       localindex = callee->localsoffset + md->paramslots;
+
+       for (i=md->paramcount-1; i>=0; --i) {
+               assert(iln);
+
+               n_ins = (iln->inlined_iinstr_cursor++);
+               assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
+
+               type = md->paramtypes[i].type;
+
+               localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
+               assert(callee->regdata);
+
+               /* translate the argument variable */
+
+               argvar = varmap[o_iptr->sx.s23.s2.args[i]];
+               assert(argvar != UNUSED);
+
+               /* remove preallocation from the argument variable */
+
+               iln->ctx->resultjd->var[argvar].flags &= ~(PREALLOC | INMEMORY);
+
+               /* check the instance slot against NULL */
+
+               if (!isstatic && i == 0) {
+                       assert(type == TYPE_ADR);
+                       n_ins->opc = ICMD_CHECKNULL;
+                       n_ins->s1.varindex = argvar;
+                       n_ins->dst.varindex = n_ins->s1.varindex;
+                       n_ins->line = o_iptr->line;
+
+                       n_ins = (iln->inlined_iinstr_cursor++);
+                       assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
+               }
+
+               /* store argument into local variable of inlined callee */
+
+               if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != UNUSED)
+               {
+                       /* this value is used in the callee */
+
+                       if (i == 0 && callee->synclocal != UNUSED) {
+                               /* we also need it for synchronization, so copy it */
+                               assert(type == TYPE_ADR);
+                               n_ins->opc = ICMD_COPY;
+                       }
+                       else {
+                               n_ins->opc = ICMD_ISTORE + type;
+                       }
+                       n_ins->s1.varindex = argvar;
+                       n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
+                       assert(n_ins->dst.varindex != UNUSED);
+               }
+               else if (i == 0 && callee->synclocal != UNUSED) {
+                       /* the value is not used inside the callee, but we need it for */
+                       /* synchronization                                             */
+                       /* XXX In this case it actually makes no sense to create a     */
+                       /*     separate synchronization variable.                      */
+
+                       n_ins->opc = ICMD_NOP;
+               }
+               else {
+                       /* this value is not used, pop it */
+
+                       n_ins->opc = ICMD_POP;
+                       n_ins->s1.varindex = argvar;
+               }
+               n_ins->line = o_iptr->line;
+
+               DOLOG( printf("%sprolog: ", iln->indent);
+                          show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
+       }
+
+       /* ASTORE for synchronized instance methods */
+
+       if (callee->synclocal != UNUSED) {
+               n_ins = (iln->inlined_iinstr_cursor++);
+               assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
+
+               n_ins->opc = ICMD_ASTORE;
+               n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
+               n_ins->dst.varindex = callee->synclocal;
+               n_ins->line = o_iptr->line;
+
+               assert(n_ins->s1.varindex != UNUSED);
+       }
+
+       /* INLINE_START instruction */
+
+       n_ins = (iln->inlined_iinstr_cursor++);
+       assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
+
+       insinfo = DNEW(insinfo_inline);
+       insinfo->method = callee->m;
+       insinfo->outer = iln->m;
+       insinfo->synclocal = callee->synclocal;
+       insinfo->synchronize = callee->synchronize;
+
+       n_ins->opc = ICMD_INLINE_START;
+       n_ins->sx.s23.s3.inlineinfo = insinfo;
+       n_ins->line = o_iptr->line;
+       iln->inline_start_instruction = n_ins;
+
+       DOLOG( printf("%sprolog: ", iln->indent);
+                  show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
+
+       return 0; /* XXX */
+}
+
+
+static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
+{
+       instruction *n_ins;
+
+       assert(iln && callee && o_iptr);
+       assert(iln->inline_start_instruction);
+
+       /* INLINE_END instruction */
+
+       n_ins = (iln->inlined_iinstr_cursor++);
+       assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
+
+       n_ins->opc = ICMD_INLINE_END;
+       n_ins->sx.s23.s3.inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
+       n_ins->line = o_iptr->line;
+
+       DOLOG( printf("%sepilog: ", iln->indent);
+                  show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
+}
+
+
+#define TRANSLATE_VAROP(vo)  \
+       n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
+
+
+static void inline_clone_instruction(inline_node *iln,
+                                                                        jitdata *jd,
+                                                                        jitdata *origjd,
+                                                                        s4 *varmap,
+                                                                        instruction *o_iptr,
+                                                                        instruction *n_iptr)
+{
+       icmdtable_entry_t *icmdt;
+       builtintable_entry *bte;
+       methoddesc *md;
+       s4 i, j;
+       branch_target_t *table;
+       lookup_target_t *lookup;
+       inline_node *scope;
+
+       *n_iptr = *o_iptr;
+
+       icmdt = &(icmd_table[o_iptr->opc]);
+
+       switch (icmdt->dataflow) {
+               case DF_0_TO_0:
+                       break;
+
+               case DF_3_TO_0:
+                       TRANSLATE_VAROP(sx.s23.s3);
+               case DF_2_TO_0:
+                       TRANSLATE_VAROP(sx.s23.s2);
+               case DF_1_TO_0:
+                       TRANSLATE_VAROP(s1);
+                       break;
+
+               case DF_2_TO_1:
+                       TRANSLATE_VAROP(sx.s23.s2);
+               case DF_1_TO_1:
+               case DF_COPY:
+               case DF_MOVE:
+                       TRANSLATE_VAROP(s1);
+               case DF_0_TO_1:
+                       TRANSLATE_VAROP(dst);
+                       break;
+
+               case DF_N_TO_1:
+                       n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
+                       for (i=0; i<n_iptr->s1.argcount; ++i) {
+                               n_iptr->sx.s23.s2.args[i] =
+                                       inline_translate_variable(jd, origjd, varmap,
+                                                       o_iptr->sx.s23.s2.args[i]);
+                       }
+                       TRANSLATE_VAROP(dst);
+                       break;
+
+               case DF_INVOKE:
+                       INSTRUCTION_GET_METHODDESC(n_iptr, md);
+clone_call:
+                       n_iptr->s1.argcount += iln->n_passthroughcount;
+                       n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
+                       for (i=0; i<o_iptr->s1.argcount; ++i) {
+                               n_iptr->sx.s23.s2.args[i] =
+                                       inline_translate_variable(jd, origjd, varmap,
+                                                       o_iptr->sx.s23.s2.args[i]);
+                       }
+                       for (scope = iln; scope != NULL; scope = scope->parent) {
+                               for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
+                                       n_iptr->sx.s23.s2.args[i++] =
+                                               scope->parent->varmap[scope->n_passthroughvars[j]];
+                               }
+                       }
+                       if (md->returntype.type != TYPE_VOID)
+                               TRANSLATE_VAROP(dst);
+                       break;
+
+               case DF_BUILTIN:
+                       bte = n_iptr->sx.s23.s3.bte;
+                       md = bte->md;
+                       goto clone_call;
+
+               default:
+                       assert(0);
+       }
+
+       switch (icmdt->controlflow) {
+               case CF_RET:
+                       TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
+                       /* FALLTHROUGH */
+               case CF_IF:
+               case CF_GOTO:
+                       inline_add_block_reference(iln, &(n_iptr->dst.block));
+                       break;
+
+               case CF_JSR:
+                       inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
+                       break;
+
+               case CF_TABLE:
+                       i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
+
+                       table = DMNEW(branch_target_t, i);
+                       MCOPY(table, o_iptr->dst.table, branch_target_t, i);
+                       n_iptr->dst.table = table;
+
+                       while (--i >= 0) {
+                               inline_add_block_reference(iln, &(table->block));
+                               table++;
+                       }
+                       break;
+
+               case CF_LOOKUP:
+                       inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
+
+                       i = n_iptr->sx.s23.s2.lookupcount;
+                       lookup = DMNEW(lookup_target_t, i);
+                       MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
+                       n_iptr->dst.lookup = lookup;
+
+                       while (--i >= 0) {
+                               inline_add_block_reference(iln, &(lookup->target.block));
+                               lookup++;
+                       }
+                       break;
+       }
+}
+
+
+static void rewrite_method(inline_node *iln)
+{
+       basicblock *o_bptr;
+       s4 len;
+       instruction *o_iptr;
+       instruction *n_iptr;
+       inline_node *nextcall;
+       basicblock *n_bptr;
+       inline_block_map *bm;
+       int i;
+       int icount;
+       jitdata *resultjd;
+       jitdata *origjd;
+       char indent[100]; /* XXX debug */
+       s4 retcount;
+       s4 retidx;
+
+       assert(iln);
+
+       resultjd = iln->ctx->resultjd;
+       origjd = iln->jd;
+
+       n_bptr = NULL;
+       nextcall = iln->children;
+
+       /* XXX debug */
+       for (i=0; i<iln->depth; ++i)
+               indent[i] = '\t';
+       indent[i] = 0;
+       iln->indent = indent;
+
+       DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
+                  printf("%s(passthrough: %d+%d)\n",
+                               indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
+                               iln->n_passthroughcount); );
+
+       /* set memory cursors */
+
+       iln->inlined_iinstr_cursor = iln->inlined_iinstr;
+       iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
+
+       /* loop over basic blocks */
+
+       o_bptr = iln->jd->basicblocks;
+       for (; o_bptr; o_bptr = o_bptr->next) {
+
+               if (o_bptr->flags < BBREACHED) {
+
+                       /* ignore the dummy end block */
+
+                       if (o_bptr->icount == 0 && o_bptr->next == NULL) {
+                               /* enter the following block as translation, for exception handler ranges */
+                               inline_block_translation(iln, o_bptr, iln->inlined_basicblocks_cursor);
+                               continue;
+                       }
+
+                       DOLOG(
+                       printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
+                                       indent,
+                                       o_bptr->nr, o_bptr->flags, o_bptr->type,
+                                       o_bptr->indepth);
+                       method_println(iln->m);
+                       );
+
+                       n_bptr = create_body_block(iln, o_bptr, iln->varmap);
+
+                       /* enter it in the blockmap */
+
+                       inline_block_translation(iln, o_bptr, n_bptr);
+
+                       close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
+                       continue;
+               }
+
+               len = o_bptr->icount;
+               o_iptr = o_bptr->iinstr;
+
+               DOLOG(
+               printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
+                               indent,
+                               o_bptr->nr, o_bptr->flags, o_bptr->type,
+                               o_bptr->indepth);
+               method_println(iln->m);
+               show_basicblock(iln->jd, o_bptr, SHOW_STACK);
+               );
+
+               if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
+                       /* create an inlined clone of this block */
+
+                       n_bptr = create_body_block(iln, o_bptr, iln->varmap);
+                       icount = 0;
+
+                       /* enter it in the blockmap */
+
+                       inline_block_translation(iln, o_bptr, n_bptr);
+               }
+               else {
+                       /* continue caller block */
+
+                       n_bptr = iln->inlined_basicblocks_cursor - 1;
+                       icount = n_bptr->icount;
+               }
+
+               retcount = 0;
+               retidx = UNUSED;
+
+               while (--len >= 0) {
+
+                       DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false,  SHOW_STACK);
+                                  printf("\n") );
+
+                       /* handle calls that will be inlined */
+
+                       if (nextcall && o_iptr == nextcall->callerins) {
+
+                               /* write the inlining prolog */
+
+                               (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
+                               icount += nextcall->prolog_instructioncount;
+
+                               /* end current block, or glue blocks together */
+
+                               n_bptr->icount = icount;
+
+                               if (nextcall->blockbefore) {
+                                       close_prolog_block(iln, n_bptr, nextcall);
+                               }
+                               else {
+                                       /* XXX */
+                               }
+
+                               /* check if the result is a local variable */
+
+                               if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
+                                               && o_iptr->dst.varindex < iln->jd->localcount)
+                               {
+                                       nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
+                               }
+                               else
+                                       nextcall->n_resultlocal = -1;
+
+                               /* set memory pointers in the callee */
+
+                               nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
+                               nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
+
+                               /* recurse */
+
+                               DOLOG( printf("%sentering inline ", indent);
+                                          show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
+
+                               rewrite_method(nextcall);
+
+                               DOLOG( printf("%sleaving inline ", indent);
+                                          show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
+
+                               /* update memory cursors */
+
+                               assert(nextcall->inlined_iinstr_cursor
+                                               <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
+                               assert(nextcall->inlined_basicblocks_cursor
+                                               == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
+                               iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
+                               iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
+
+                               /* start new block, or glue blocks together */
+
+                               if (nextcall->blockafter) {
+                                       n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
+                                       icount = 0;
+                               }
+                               else {
+                                       n_bptr = iln->inlined_basicblocks_cursor - 1;
+                                       icount = n_bptr->icount;
+                                       /* XXX */
+                               }
+
+                               /* emit inlining epilog */
+
+                               emit_inlining_epilog(iln, nextcall, o_iptr);
+                               icount++; /* XXX epilog instructions */
+
+                               /* proceed to next call */
+
+                               nextcall = nextcall->next;
+                       }
+                       else {
+                               n_iptr = (iln->inlined_iinstr_cursor++);
+                               assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
+
+                               switch (o_iptr->opc) {
+                                       case ICMD_RETURN:
+                                               if (iln->depth == 0)
+                                                       goto default_clone;
+                                               goto return_tail;
+
+                                       case ICMD_IRETURN:
+                                       case ICMD_ARETURN:
+                                       case ICMD_LRETURN:
+                                       case ICMD_FRETURN:
+                                       case ICMD_DRETURN:
+                                               if (iln->depth == 0)
+                                                       goto default_clone;
+                                               retcount = 1;
+                                               retidx = iln->varmap[o_iptr->s1.varindex];
+                                               if (iln->n_resultlocal != -1) {
+                                                       /* store result in a local variable */
+
+                                                       DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
+                                                       /* This relies on the same sequence of types for */
+                                                       /* ?STORE and ?RETURN opcodes.                   */
+                                                       n_iptr->opc = ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN);
+                                                       n_iptr->s1.varindex = retidx;
+                                                       n_iptr->dst.varindex = iln->n_resultlocal;
+
+                                                       retcount = 0;
+                                                       retidx = UNUSED;
+
+                                                       n_iptr = (iln->inlined_iinstr_cursor++);
+                                                       assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
+                                                       icount++;
+                                               }
+                                               else if ((retidx < resultjd->localcount && iln->blockafter)
+                                                               || !iln->blockafter) /* XXX do we really always need the MOVE? */
+                                               {
+                                                       /* local must not become outvar, insert a MOVE */
+
+                                                       n_iptr->opc = ICMD_MOVE;
+                                                       n_iptr->s1.varindex = retidx;
+                                                       retidx = inline_new_temp_variable(resultjd,
+                                                                                                                         resultjd->var[retidx].type);
+                                                       n_iptr->dst.varindex = retidx;
+
+                                                       n_iptr = (iln->inlined_iinstr_cursor++);
+                                                       assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
+                                                       icount++;
+                                               }
+return_tail:
+                                               if (iln->blockafter) {
+                                                       n_iptr->opc = ICMD_GOTO;
+                                                       n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
+                                                       inline_add_block_reference(iln, &(n_iptr->dst.block));
+                                               }
+                                               else {
+                                                       n_iptr->opc = ICMD_NOP;
+                                               }
+                                               break;
+#if 0
+                                               if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
+                                                       n_iptr->opc = ICMD_NOP;
+                                                       break;
+                                               }
+                                               goto default_clone;
+                                               break;
+#endif
+
+                                       default:
+default_clone:
+                                               inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
+                               }
+
+                               DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
+                                          printf("\n"););
+
+                               icount++;
+                       }
+
+                       o_iptr++;
+               }
+
+               /* end of basic block */
+
+               if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
+                       close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
+                       n_bptr->icount = icount;
+
+                       DOLOG( printf("closed body block:\n");
+                                  show_basicblock(resultjd, n_bptr, SHOW_STACK); );
+               }
+               else {
+                       n_bptr->icount = icount;
+                       assert(iln->parent);
+                       if (retidx != UNUSED)
+                               iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
+               }
+       }
+
+       bm = iln->ctx->blockmap;
+       for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
+               assert(bm->iln && bm->o_block && bm->n_block);
+               if (bm->iln == iln)
+                       inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block);
+       }
+
+#if !defined(NDEBUG)
+       if (iln->refs) {
+               inline_target_ref *ref;
+               ref = iln->refs;
+               while (ref) {
+                       if (!iln->depth || *(ref->ref) != INLINE_RETURN_REFERENCE(iln)) {
+                               DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
+                                          (void*)*(ref->ref)) );
+                               assert(false);
+                       }
+                       ref = ref->next;
+               }
+       }
+#endif
+}
+
+
+static exception_entry * inline_exception_tables(inline_node *iln,
+                                                                                                exception_entry *n_extable,
+                                                                                                exception_entry **prevextable)
+{
+       inline_node *child;
+       inline_node *scope;
+       exception_entry *et;
+
+       assert(iln);
+       assert(n_extable);
+       assert(prevextable);
+
+       child = iln->children;
+       if (child) {
+               do {
+                       n_extable = inline_exception_tables(child, n_extable, prevextable);
+                       child = child->next;
+               } while (child != iln->children);
+       }
+
+       et = iln->jd->exceptiontable;
+       for (; et != NULL; et = et->down) {
+               assert(et);
+               MZERO(n_extable, exception_entry, 1);
+               n_extable->start     = inline_map_block(iln, et->start  , iln);
+               n_extable->end       = inline_map_block(iln, et->end    , iln);
+               n_extable->handler   = inline_map_block(iln, et->handler, iln);
+               n_extable->catchtype = et->catchtype;
+
+               if (*prevextable) {
+                       (*prevextable)->down = n_extable;
+               }
+               *prevextable = n_extable;
+
+               n_extable++;
+       }
+
+       if (iln->handler_monitorexit) {
+               exception_entry **activehandlers;
+
+               MZERO(n_extable, exception_entry, 1);
+               n_extable->start   = iln->inlined_basicblocks;
+               n_extable->end     = iln->inlined_basicblocks_cursor;
+               n_extable->handler = iln->handler_monitorexit;
+               n_extable->catchtype.any = NULL; /* finally */
+
+               if (*prevextable) {
+                       (*prevextable)->down = n_extable;
+               }
+               *prevextable = n_extable;
+
+               n_extable++;
+
+               /* We have to protect the created handler with the same handlers */
+               /* that protect the method body itself.                          */
+
+               for (scope = iln; scope->parent != NULL; scope = scope->parent) {
+
+                       activehandlers = scope->o_handlers;
+                       assert(activehandlers);
+
+                       while (*activehandlers) {
+
+                               assert(scope->parent);
+
+                               MZERO(n_extable, exception_entry, 1);
+                               n_extable->start     = iln->handler_monitorexit;
+                               n_extable->end       = iln->handler_monitorexit + 1; /* XXX ok in this case? */
+                               n_extable->handler   = inline_map_block(scope->parent,
+                                                                                                               (*activehandlers)->handler,
+                                                                                                               scope->parent);
+                               n_extable->catchtype = (*activehandlers)->catchtype;
+
+                               if (*prevextable) {
+                                       (*prevextable)->down = n_extable;
                                }
-                               
-                               DOLOG( debug_dump_inline_context(iln) );
-                               iln->ctx->o_translationlimit = o_nexttorewrite;
-                                       
-                               /* emit inlining epilog */
-                               emit_inlining_epilog(iln,nextcall,n_sp,o_iptr);
-                               icount++; /* XXX epilog instructions */
+                               *prevextable = n_extable;
 
-                               /* proceed to next call */
-                               nextcall = nextcall->next;
+                               n_extable++;
+                               activehandlers++;
+                       }
+               }
+       }
+
+       return n_extable;
+}
+
+
+static void inline_locals(inline_node *iln)
+{
+       inline_node *child;
+
+       assert(iln);
+
+       iln->varmap = create_variable_map(iln);
+
+       child = iln->children;
+       if (child) {
+               do {
+                       inline_locals(child);
+                       child = child->next;
+               } while (child != iln->children);
+       }
+
+       if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
+               iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
+       if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
+               iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
+       if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
+               iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
+}
+
+
+static void inline_interface_variables(inline_node *iln)
+{
+       basicblock *bptr;
+       jitdata *resultjd;
+       s4 i;
+       varinfo *v;
+
+       resultjd = iln->ctx->resultjd;
+
+       resultjd->interface_map = DMNEW(interface_info, 5*iln->ctx->maxinoutdepth);
+       for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
+               resultjd->interface_map[i].flags = UNUSED;
+
+       for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
+               assert(bptr->indepth  <= iln->ctx->maxinoutdepth);
+               assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
 
-                               DOLOG(
-                               printf("resuming old L%03d (flags=%d,type=%d,os=%p,oid=%d,ois=%p,cursor=%d,curreloc=%d,callerstack=%d) of ",
-                                               o_bptr->debug_nr,o_bptr->flags,o_bptr->type,
-                                               (void*)o_bptr->stack,o_bptr->indepth,(void*)o_bptr->instack,
-                                               DEBUG_SLOT(iln->n_inlined_stack_cursor),(int)curreloc,
-                                               DEBUG_SLOT(iln->n_callerstack));
-                               method_println(iln->m);
-                               );
+               for (i=0; i<bptr->indepth; ++i) {
+                       v = &(resultjd->var[bptr->invars[i]]);
+                       v->flags |= INOUT;
+                       v->flags &= ~PREALLOC;
+                       v->flags &= ~INMEMORY;
+                       assert(bptr->invars[i] >= resultjd->localcount);
+
+                       if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
+                               resultjd->interface_map[5*i + v->type].flags = v->flags;
                        }
                        else {
-                               emit_instruction(iln,o_iptr,curreloc,o_curstack);
-                               icount++;
-
-                               if (o_dst > o_lasttorewrite)
-                                       o_lasttorewrite = o_dst;
+                               resultjd->interface_map[5*i + v->type].flags |= v->flags;
                        }
+               }
 
-                       DOLOG( printf("o_dst = %p\n",(void*)o_dst) );
-                       o_curstack = o_dst;
-                       o_iptr++;
+               for (i=0; i<bptr->outdepth; ++i) {
+                       v = &(resultjd->var[bptr->outvars[i]]);
+                       v->flags |= INOUT;
+                       v->flags &= ~PREALLOC;
+                       v->flags &= ~INMEMORY;
+                       assert(bptr->outvars[i] >= resultjd->localcount);
+
+                       if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
+                               resultjd->interface_map[5*i + v->type].flags = v->flags;
+                       }
+                       else {
+                               resultjd->interface_map[5*i + v->type].flags |= v->flags;
+                       }
                }
+       }
+}
 
-               /* end of basic block */
-               /* rewrite stack after last call */
-               if (o_nexttorewrite <= o_lasttorewrite) {
-                       rewrite_stack(iln,o_nexttorewrite,o_lasttorewrite,curreloc);
+
+static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
+{
+       basicblock *n_bptr;
+       instruction *n_ins;
+       inline_node *child;
+       builtintable_entry *bte;
+       s4 exvar;
+       s4 syncvar;
+       varinfo vinfo;
+       s4 i;
+
+       child = iln->children;
+       if (child) {
+               do {
+                       inline_write_exception_handlers(master, child);
+                       child = child->next;
+               } while (child != iln->children);
+       }
+
+       if (iln->synchronize) {
+               /* create the monitorexit handler */
+               n_bptr = create_block(master, iln, iln, NULL, NULL,
+                                                         iln->n_passthroughcount + 1);
+               n_bptr->type = BBTYPE_EXH;
+               n_bptr->flags = BBFINISHED;
+
+               exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
+               n_bptr->invars[iln->n_passthroughcount] = exvar;
+
+               iln->handler_monitorexit = n_bptr;
+
+               /* ACONST / ALOAD */
+
+               n_ins = master->inlined_iinstr_cursor++;
+               if (iln->m->flags & ACC_STATIC) {
+                       n_ins->opc = ICMD_ACONST;
+                       n_ins->sx.val.c.cls = iln->m->class;
+                       n_ins->flags.bits = INS_FLAG_CLASS;
                }
-               n_bptr->outstack = relocate_stack_ptr(iln,o_bptr->outstack,curreloc);
-               n_bptr->outdepth = iln->n_callerstackdepth + o_bptr->outdepth;
-               assert(n_bptr->outdepth == stack_depth(n_bptr->outstack));
-#if 0
-               if (n_bptr->outstack) {
-                       assert(curreloc);
-                       n_bptr->outstack += curreloc;
+               else {
+                       n_ins->opc = ICMD_ALOAD;
+                       n_ins->s1.varindex = iln->synclocal;
+                       assert(n_ins->s1.varindex != UNUSED);
+               }
+               /* XXX could be PREALLOCed for  builtin call */
+               syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
+               n_ins->dst.varindex = syncvar;
+               n_ins->line = 0;
+
+               /* MONITOREXIT */
+
+               bte = builtintable_get_internal(LOCK_monitor_exit);
+
+               n_ins = master->inlined_iinstr_cursor++;
+               n_ins->opc = ICMD_BUILTIN;
+               n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
+               n_ins->sx.s23.s2.args = DMNEW(s4, n_ins->s1.argcount);
+               n_ins->sx.s23.s2.args[0] = syncvar;
+               for (i=0; i < iln->n_passthroughcount + 1; ++i) {
+                       n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
                }
+               n_ins->sx.s23.s3.bte = bte;
+               n_ins->line = 0;
+
+               /* ATHROW */
+
+               n_ins = master->inlined_iinstr_cursor++;
+               n_ins->opc = ICMD_ATHROW;
+               n_ins->flags.bits = 0;
+               n_ins->s1.varindex = exvar;
+               n_ins->line = 0;
+
+               /* close basic block */
+
+               close_block(iln, iln, n_bptr, iln->n_passthroughcount);
+               n_bptr->icount = 3;
+       }
+}
+
+
+/* second pass driver *********************************************************/
+
+static bool test_inlining(inline_node *iln, jitdata *jd,
+               jitdata **resultjd)
+{
+       instruction *n_ins;
+       basicblock *n_bb;
+       basicblock *n_bptr;
+       exception_entry *n_ext;
+       exception_entry *prevext;
+       codegendata *n_cd;
+       jitdata *n_jd;
+       s4 i;
+
+
+       static int debug_verify_inlined_code = 1; /* XXX */
+#if !defined(NDEBUG)
+       static int debug_compile_inlined_code_counter = 0;
 #endif
-               n_bptr->icount = icount;
-
-               n_iptr = iln->inlined_iinstr_cursor - 1;
-               if (n_iptr->opc == ICMD_INLINE_GOTO) {
-                       DOLOG( printf("creating stack slot for ICMD_INLINE_GOTO\n") );
-                       n_sp = iln->n_inlined_stack_cursor++;
-                       assert(n_iptr->dst);
-                       *n_sp = *n_iptr->dst;
-                       n_sp->prev = iln->n_callerstack;
-                       n_iptr->dst = n_sp;
-
-                       n_bptr->outdepth = iln->n_callerstackdepth + 1;
-                       n_bptr->outstack = n_sp;
+
+       DOLOG( dump_inline_tree(iln, 0); );
+
+       assert(iln && jd && resultjd);
+
+       *resultjd = jd;
+
+       n_ins = DMNEW(instruction, iln->cumul_instructioncount);
+       iln->inlined_iinstr = n_ins;
+
+       n_bb = DMNEW(basicblock, iln->cumul_basicblockcount);
+       MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
+       iln->inlined_basicblocks = n_bb;
+
+       iln->ctx->blockmap = DMNEW(inline_block_map, iln->cumul_blockmapcount);
+
+       n_jd = jit_jitdata_new(iln->m);
+       n_jd->flags = jd->flags;
+       iln->ctx->resultjd = n_jd;
+
+       reg_setup(n_jd);
+
+       /* create the local_map */
+
+       n_jd->local_map = DMNEW(s4, 5*iln->cumul_maxlocals);
+       for (i=0; i<5*iln->cumul_maxlocals; ++i)
+               n_jd->local_map[i] = UNUSED;
+
+       /* create / coalesce local variables */
+
+       n_jd->varcount = 0;
+       n_jd->vartop = 0;
+       n_jd->var = NULL;
+
+       inline_locals(iln);
+
+       n_jd->localcount = n_jd->vartop;
+
+       /* extra variables for verification (DEBUG) */
+
+       if (debug_verify_inlined_code) {
+               n_jd->vartop   += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
+               if (n_jd->vartop > n_jd->varcount) {
+                       /* XXX why? */
+                       n_jd->var = DMREALLOC(n_jd->var, varinfo, n_jd->varcount, n_jd->vartop);
+                       n_jd->varcount = n_jd->vartop;
                }
        }
 
-       bm = iln->ctx->blockmap;
-       for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
-               assert(bm->iln && bm->o_block && bm->n_block);
-               if (bm->iln != iln)
-                       continue;
-               inline_resolve_block_refs(&(iln->refs),iln->ctx->blockmap[i].o_block,iln->ctx->blockmap[i].n_block);
+       /* write inlined code */
+
+       rewrite_method(iln);
+
+       /* create exception handlers */
+
+       inline_write_exception_handlers(iln, iln);
+
+       /* write the dummy end block */
+
+       n_bptr = create_block(iln, iln, iln, NULL, NULL, 0);
+       n_bptr->flags = BBUNDEF;
+       n_bptr->type = BBTYPE_STD;
+
+       /* store created code in jitdata */
+
+       n_jd->basicblocks = iln->inlined_basicblocks;
+       n_jd->basicblockindex = NULL;
+       n_jd->instructioncount = iln->cumul_instructioncount;
+       n_jd->instructions = iln->inlined_iinstr;
+
+       /* link the basic blocks (dummy end block is not counted) */
+
+       n_jd->basicblockcount = (iln->inlined_basicblocks_cursor - iln->inlined_basicblocks) - 1;
+       for (i=0; i<n_jd->basicblockcount + 1; ++i)
+               n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
+       if (i)
+               n_jd->basicblocks[i-1].next = NULL;
+
+       /* check basicblock numbers */
+
+#if !defined(NDEBUG)
+       jit_check_basicblock_numbers(n_jd);
+#endif
+
+       /* create the exception table */
+
+       if (iln->cumul_exceptiontablelength) {
+               exception_entry *tableend;
+
+               n_ext = DMNEW(exception_entry, iln->cumul_exceptiontablelength);
+               prevext = NULL;
+               tableend = inline_exception_tables(iln, n_ext, &prevext);
+               assert(tableend == n_ext + iln->cumul_exceptiontablelength);
+               if (prevext)
+                       prevext->down = NULL;
+
+               n_jd->exceptiontablelength = iln->cumul_exceptiontablelength;
+               n_jd->exceptiontable = n_ext;
+       }
+       else {
+               n_ext = NULL;
        }
 
-#ifndef NDEBUG
-       if (iln->refs) {
-               inline_target_ref *ref;
-               ref = iln->refs;
-               while (ref) {
-                       if (!iln->depth || *(ref->ref) != (void*) (ptrint) (0x333 + iln->depth) /* XXX */) {
-                               DOLOG( printf("XXX REMAINING REF at depth %d: %p\n",iln->depth,(void*)*(ref->ref)) );
-                               assert(false);
-                       }
-                       ref = ref->next;
+       /*******************************************************************************/
+
+       n_cd = n_jd->cd;
+       memcpy(n_cd, jd->cd, sizeof(codegendata));
+
+       n_cd->method = NULL; /* XXX */
+       n_cd->maxlocals = iln->cumul_maxlocals;
+       n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
+
+       inline_post_process(n_jd);
+
+       inline_interface_variables(iln);
+
+#if defined(ENABLE_VERIFIER)
+       if (debug_verify_inlined_code) {
+               debug_verify_inlined_code = 0;
+               DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
+               if (!typecheck(n_jd)) {
+                       *exceptionptr = NULL;
+                       DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
+                       return false;
+               }
+               else {
+                       DOLOG( printf("VERIFICATION PASSED.\n") );
                }
+               debug_verify_inlined_code = 1;
+       }
+#endif /* defined(ENABLE_VERIFIER) */
+
+       /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
+
+       n_jd->rd->freemem = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
+#if defined(HAS_4BYTE_STACKSLOT)
+       n_jd->rd->freemem_2 = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
+#endif
+
+#if !defined(NDEBUG)
+       if (n_jd->instructioncount >= inline_debug_min_size
+                       && n_jd->instructioncount <= inline_debug_max_size)
+       {
+          if (debug_compile_inlined_code_counter >= inline_debug_start_counter
+                          && debug_compile_inlined_code_counter <= inline_debug_end_counter)
+#endif /* NDEBUG */
+          {
+                       *resultjd = n_jd;
+
+#if !defined(NDEBUG)
+                       inline_count_methods++;
+
+                       /* inline_debug_log++; */
+                       DOLOG(
+                       printf("==== %d.INLINE ==================================================================\n", debug_compile_inlined_code_counter);
+                       printf("\ninline tree:\n");
+                       dump_inline_tree(iln, 0);
+                       n_jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE | JITDATA_FLAG_SHOWDISASSEMBLE;
+                       /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
+                       printf("-------- DONE -----------------------------------------------------------\n");
+                       fflush(stdout);
+                       );
+                       /* inline_debug_log--; */
+#endif
+          }
+
+#if !defined(NDEBUG)
+               debug_compile_inlined_code_counter++;
        }
 #endif
+       return true;
 }
 
-static basicblock * inline_map_block(inline_node *iln,basicblock *o_block,inline_node *targetiln)
-{
-       inline_block_map *bm;
-       inline_block_map *bmend;
-       
-       assert(iln);
-       assert(targetiln);
-       
-       if (!o_block)
-               return NULL;
 
-       bm = iln->ctx->blockmap;
-       bmend = bm + iln->ctx->blockmap_index;
+/* first pass: build inlining tree ********************************************/
+
+static bool inline_analyse_callee(inline_node *caller,
+                                                                 methodinfo *callee,
+                                                                 basicblock *callerblock,
+                                                                 instruction *calleriptr,
+                                                                 s4 callerpc,
+                                                                 exception_entry **handlers,
+                                                                 s4 nhandlers)
+{
+       inline_node *cn;              /* the callee inline_node */
+       s4           argi;
+       bool         isstatic;
+       s4           i, j;
+       basicblock  *bptr;
+       instruction *iptr;
+
+       /* create an inline tree node */
+
+       cn = DNEW(inline_node);
+       MZERO(cn, inline_node, 1);
+
+       cn->ctx = caller->ctx;
+       cn->m = callee;
+       cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
+       isstatic = (callee->flags & ACC_STATIC);
+
+       /* get the intermediate representation of the callee */
+
+       if (!inline_jit_compile(cn))
+               return false;
+
+       /* info about the call site */
+
+       cn->depth = caller->depth + 1;
+       cn->callerblock = callerblock;
+       cn->callerins = calleriptr;
+       cn->callerpc = callerpc;
+       cn->o_handlers = handlers;
+       cn->n_handlercount = caller->n_handlercount + nhandlers;
+
+       /* determine if we need basic block boundaries before/after */
+
+       cn->blockbefore = false;
+       cn->blockafter = false;
+
+       if (cn->jd->branchtoentry)
+               cn->blockbefore = true;
+
+       if (cn->jd->branchtoend)
+               cn->blockafter = true;
 
-       while (bm < bmend) {
-               assert(bm->iln && bm->o_block && bm->n_block);
-               if (bm->o_block == o_block && bm->iln == targetiln)
-                       return bm->n_block;
-               bm++;
-       }
+       if (cn->jd->returncount > 1)
+               cn->blockafter = true;
 
-       assert(false);
-       return NULL; /* not reached */
-}
+       /* XXX make safer and reusable (maybe store last real block) */
+       for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
+               ;
 
-static exceptiontable * inline_exception_tables(inline_node *iln,exceptiontable *n_extable,exceptiontable **prevextable)
-{
-       inline_node *child;
-       exceptiontable *et;
-       int i;
-       
-       assert(iln);
-       assert(n_extable);
-       assert(prevextable);
+       if (cn->jd->returnblock != bptr)
+               cn->blockafter = true;
 
-       child = iln->children;
-       if (child) {
-               do {
-                       n_extable = inline_exception_tables(child,n_extable,prevextable);
-                       child = child->next;
-               } while (child != iln->children);
-       }
+       /* info about the callee */
 
-       et = iln->m->exceptiontable;
-       for (i=0; i<iln->m->exceptiontablelength; ++i) {
-               assert(et);
-               memset(n_extable,0,sizeof(exceptiontable));
-               n_extable->startpc = et->startpc;
-               n_extable->endpc = et->endpc;
-               n_extable->handlerpc = et->handlerpc;
-               n_extable->start = inline_map_block(iln,et->start,iln);
-               n_extable->end = inline_map_block(iln,et->end,iln);
-               n_extable->handler = inline_map_block(iln,et->handler,iln);
-               n_extable->catchtype = et->catchtype;
+       cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
+       cn->prolog_instructioncount = callee->parseddesc->paramcount + 1;
+       cn->epilog_instructioncount = 1; /* INLINE_END */
+       cn->extra_instructioncount = 0;
 
-               if (*prevextable) {
-                       (*prevextable)->down = n_extable;
-               }
-               *prevextable = n_extable;
-               
-               n_extable++;
-               et++;
-       }
+       /* we need a CHECKNULL for instance methods */
 
-       if (iln->handler_monitorexit) {
-               exceptiontable **activehandlers;
-                       
-               memset(n_extable,0,sizeof(exceptiontable));
-               n_extable->startpc = 0; /* XXX */
-               n_extable->endpc = 0; /* XXX */
-               n_extable->handlerpc = 0; /* XXX */
-               n_extable->start = iln->inlined_basicblocks;
-               n_extable->end = iln->inlined_basicblocks_cursor;
-               n_extable->handler = iln->handler_monitorexit;
-               n_extable->catchtype.any = NULL; /* finally */
+       if (!isstatic)
+               cn->prolog_instructioncount += 1;
 
-               if (*prevextable) {
-                       (*prevextable)->down = n_extable;
-               }
-               *prevextable = n_extable;
-               
-               n_extable++;
+       /* deal with synchronized callees */
 
-               activehandlers = iln->o_handlers;
-               while (*activehandlers) {
+       if (cn->synchronize) {
+               methoddesc         *md;
+               builtintable_entry *bte;
 
-                       assert(iln->parent);
+               /* we need basic block boundaries because of the handler */
 
-                       memset(n_extable,0,sizeof(exceptiontable));
-                       n_extable->startpc = 0; /* XXX */
-                       n_extable->endpc = 0; /* XXX */
-                       n_extable->handlerpc = 0; /* XXX */
-                       n_extable->start = iln->handler_monitorexit;
-                       n_extable->end = iln->handler_monitorexit + 1;
-                       n_extable->handler = inline_map_block(iln->parent,(*activehandlers)->handler,iln->parent);
-                       n_extable->catchtype = (*activehandlers)->catchtype;
-
-                       if (*prevextable) {
-                               (*prevextable)->down = n_extable;
-                       }
-                       *prevextable = n_extable;
+               cn->blockbefore = true;
+               cn->blockafter = true;
+
+               /* for synchronized instance methods */
+               /* we need an ASTORE in the prolog   */
 
-                       n_extable++;
-                       activehandlers++;
+               if (!isstatic) {
+                       cn->prolog_instructioncount += 1;
+                       cn->localsoffset += 1;
                }
-               
-       }
 
-       return n_extable;
-}
+               /* and exception handler */
+               /* ALOAD, builtin_monitorexit, ATHROW */
 
-static void inline_locals(inline_node *iln,registerdata *rd)
-{
-       int i;
-       int t;
-       inline_node *child;
+               cn->extra_instructioncount += 3;
 
-       assert(iln);
-       assert(rd);
+               /* exception table entries */
 
-       child = iln->children;
-       if (child) {
-               do {
-                       inline_locals(child,rd);
-                       child = child->next;
-               } while (child != iln->children);
+               caller->cumul_exceptiontablelength += 1 + cn->n_handlercount;
+
+               /* we must call the builtins */
+
+               bte = builtintable_get_internal(LOCK_monitor_enter);
+               md = bte->md;
+               if (md->memuse > cn->regdata->memuse)
+                       cn->regdata->memuse = md->memuse;
+               if (md->argintreguse > cn->regdata->argintreguse)
+                       cn->regdata->argintreguse = md->argintreguse;
+
+               bte = builtintable_get_internal(LOCK_monitor_exit);
+               md = bte->md;
+               if (md->memuse > cn->regdata->memuse)
+                       cn->regdata->memuse = md->memuse;
+               if (md->argintreguse > cn->regdata->argintreguse)
+                       cn->regdata->argintreguse = md->argintreguse;
+
+               caller->ctx->calls_others = true;
        }
 
-       assert(iln->regdata);
+       /* determine pass-through variables */
 
-       for (i=0; i<iln->m->maxlocals; ++i) {
-               for (t=TYPE_INT; t<=TYPE_ADR; ++t) {
-                       DOLOG( printf("local %d type=%d in ",i,iln->regdata->locals[i][t].type); method_println(iln->m); );
-                       if (iln->regdata->locals[i][t].type >= 0) {
-                               rd->locals[iln->localsoffset + i][t].type = iln->regdata->locals[i][t].type;
-                               rd->locals[iln->localsoffset + i][t].flags |= iln->regdata->locals[i][t].flags;
-                       }
+       i = calleriptr->s1.argcount - callee->parseddesc->paramcount; /* max # of pass-though vars */
+
+       cn->n_passthroughvars = DMNEW(s4, i);
+       j = 0;
+       for (argi = calleriptr->s1.argcount - 1; argi >= callee->parseddesc->paramcount; --argi) {
+               s4 idx = calleriptr->sx.s23.s2.args[argi];
+               if (idx >= caller->jd->localcount) {
+                       cn->n_passthroughvars[j] = idx;
+                       j++;
+               }
+               else {
+                       DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
                }
        }
+       assert(j <= i);
+       cn->n_selfpassthroughcount = j;
+       cn->n_passthroughcount = caller->n_passthroughcount + cn->n_selfpassthroughcount;
 
-       if (iln->regdata->memuse > rd->memuse)
-               rd->memuse = iln->regdata->memuse;
-       if (iln->regdata->argintreguse > rd->argintreguse)
-               rd->argintreguse = iln->regdata->argintreguse;
-       if (iln->regdata->argfltreguse > rd->argfltreguse)
-               rd->argfltreguse = iln->regdata->argfltreguse;
-}
+       /* insert the node into the inline tree */
 
-static void inline_stack_interfaces(inline_node *iln,registerdata *rd)
-{
-       int i;
-       int d;
-       basicblock *bptr;
-       stackptr sp;
+       insert_inline_node(caller, cn);
 
-       assert(iln);
-       assert(rd);
-       assert(rd->interfaces);
-
-       bptr = iln->inlined_basicblocks;
-       for (i=0; i<iln->cumul_basicblockcount; ++i, ++bptr) {
-               DOLOG( printf("INLINE STACK INTERFACE block L%03d\n",bptr->debug_nr) );
-               DOLOG( printf("\toutstack = ");debug_dump_stack(bptr->outstack);printf("\n") );
-               DOLOG( printf("\tinstack = ");debug_dump_stack(bptr->outstack);printf("\n") );
-
-               assert(bptr->outdepth == stack_depth(bptr->outstack));
-               assert(bptr->indepth == stack_depth(bptr->instack));
-               
-               sp = bptr->outstack;
-               d = bptr->outdepth - 1;
-               while (sp) {
-                       if ((sp->varkind == STACKVAR) && (sp->varnum > d)) {
-                               sp->varkind = TEMPVAR;
-                       }
-                       else {
-                               sp->varkind = STACKVAR;
-                               sp->varnum = d;
-                       }
-                       DOLOG( printf("INLINE STACK INTERFACE L%03d outstack d=%d varkind=%d varnum=%d type=%d flags=%01x\n",
-                                       bptr->debug_nr,d,sp->varkind,sp->varnum,sp->type,sp->flags) );
-                       rd->interfaces[d][sp->type].type = sp->type;
-                       rd->interfaces[d][sp->type].flags |= sp->flags;
-                       d--;
-                       sp = sp->prev;
-               }
+       /* analyse recursively */
 
-               sp = bptr->instack;
-               d = bptr->indepth - 1;
-               while (sp) {
-                       rd->interfaces[d][sp->type].type = sp->type;
-                       if (sp->varkind == STACKVAR && (sp->flags & SAVEDVAR)) {
-                               rd->interfaces[d][sp->type].flags |= SAVEDVAR;
-                       }
-                       DOLOG( printf("INLINE STACK INTERFACE L%03d instack d=%d varkind=%d varnum=%d type=%d flags=%01x\n",
-                                       bptr->debug_nr,d,sp->varkind,sp->varnum,sp->type,sp->flags) );
-                       d--;
-                       sp = sp->prev;
-               }
+       if (!inline_inline_intern(callee, cn))
+               return false;
+
+       /* subtract one block if we continue the caller block */
+
+       if (!cn->blockbefore)
+               cn->cumul_basicblockcount -= 1;
+
+       /* add exception handler block for synchronized callees */
+
+       if (cn->synchronize) {
+               caller->ctx->master->cumul_basicblockcount++;
+               caller->ctx->master->cumul_blockmapcount++;
+       }
+
+       /* cumulate counters */
+
+       caller->cumul_instructioncount += cn->prolog_instructioncount;
+       caller->cumul_instructioncount += cn->epilog_instructioncount;
+       caller->cumul_instructioncount += cn->extra_instructioncount;
+       caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
+
+       caller->cumul_basicblockcount += cn->cumul_basicblockcount;
+       caller->cumul_blockmapcount += cn->cumul_blockmapcount;
+       caller->cumul_exceptiontablelength += cn->cumul_exceptiontablelength;
+       if (cn->cumul_maxlocals > caller->cumul_maxlocals)
+               caller->cumul_maxlocals = cn->cumul_maxlocals;
+
+       if (caller->cumul_basicblockcount > 10*caller->ctx->master->jd->basicblockcount) {
+#if 0
+               printf("STOPPING to avoid code explosion (%d blocks)\n",
+                               caller->cumul_basicblockcount);
+#endif
+               return false;
+       }
+
+       /* XXX extra block after inlined call */
+       if (cn->blockafter) {
+               caller->cumul_basicblockcount += 1;
+               caller->cumul_blockmapcount += 1;
        }
+
+       return true;
 }
 
-static bool inline_inline_intern(methodinfo *m,jitdata *jd, inline_node *iln)
+
+static bool inline_inline_intern(methodinfo *m, inline_node *iln)
 {
        basicblock *bptr;
        s4 len;
        instruction *iptr;
-       stackptr o_dst;
-       stackptr o_curstack;
        int opcode;                                   /* invocation opcode */
        methodinfo *callee;
-       inline_node *calleenode;
        inline_node *active;
-       stackptr sp;
-       s4 i;
-       bool isstatic;
-       exceptiontable **handlers;
+       exception_entry **handlers;
+       exception_entry *ex;
        s4 nhandlers;
+       jitdata *mjd;
+       bool speculative;
 
-       assert(jd);
        assert(iln);
 
+       mjd = iln->jd;
+
        /* initialize cumulative counters */
-       
-       iln->cumul_maxstack = iln->n_callerstackdepth + m->maxstack + 1 /* XXX builtins */;
+
        iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
-       iln->cumul_exceptiontablelength += m->exceptiontablelength;
+       iln->cumul_exceptiontablelength += mjd->exceptiontablelength;
 
        /* iterate over basic blocks */
 
-       bptr = m->basicblocks;
-       for (; bptr; bptr = bptr->next) {
+       for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
 
-               iln->cumul_basicblockcount++;
+               /* ignore dummy end blocks (but count them for the blockmap) */
 
-               /* extra stackslots */
-               iln->cumul_stackcount += iln->n_callerstackdepth;
+               iln->cumul_blockmapcount++;
+               if (bptr->icount > 0 || bptr->next != NULL)
+                       iln->cumul_basicblockcount++;
+
+               /* skip dead code */
 
                if (bptr->flags < BBREACHED)
                        continue;
 
                /* allocate the buffer of active exception handlers */
                /* XXX this wastes some memory, but probably it does not matter */
-       
-               handlers = DMNEW(exceptiontable*, m->exceptiontablelength + 1);
+
+               handlers = DMNEW(exception_entry*, mjd->exceptiontablelength + 1);
 
                /* determine the active exception handlers for this block     */
                /* XXX maybe the handlers of a block should be part of our IR */
+               /* XXX this should share code with the type checkers          */
                nhandlers = 0;
-               for (i = 0; i < m->exceptiontablelength; ++i) {
-                       if ((m->exceptiontable[i].start <= bptr) && (m->exceptiontable[i].end > bptr)) {
-                               handlers[nhandlers++] = m->exceptiontable + i;
+               for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
+                       if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
+                               handlers[nhandlers++] = ex;
                        }
                }
                handlers[nhandlers] = NULL;
 
-               assert(bptr->stack);
-               
                len = bptr->icount;
                iptr = bptr->iinstr;
-               o_curstack = bptr->instack;
 
                iln->instructioncount += len;
                iln->cumul_instructioncount += len;
 
-#if 0
-               printf("ADD INSTRUCTIONS [%d]: %d, count=%d, cumulcount=%d\n",
-                               iln->depth,len,iln->instructioncount,iln->cumul_instructioncount);
-#endif
-
-               while (--len >= 0) {
+               for (; --len >= 0; ++iptr) {
 
                        opcode = iptr->opc;
-                       o_dst = iptr->dst;
 
                        switch (opcode) {
-                               case ICMD_IINC:
-                                       /* XXX we cannot deal with IINC's stack hacking */
-                                       return false;
-
-                               case ICMD_LOOKUPSWITCH:
-                               case ICMD_TABLESWITCH:
-                                       /* XXX these are not implemented, yet. */
-                                       return false;
-                               
                                /****************************************/
                                /* INVOKATIONS                          */
 
@@ -1356,431 +2090,285 @@ static bool inline_inline_intern(methodinfo *m,jitdata *jd, inline_node *iln)
                                case ICMD_INVOKESPECIAL:
                                case ICMD_INVOKESTATIC:
                                case ICMD_INVOKEINTERFACE:
-                                       callee = (methodinfo *) iptr[0].val.a;
 
-                                       if (callee) {
-                                               if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE) || opcode == ICMD_INVOKESPECIAL)
-                                                   && !(callee->flags & (ACC_NATIVE))) 
-                                               {
-                                                       if (iln->depth < 3) {
-                                                               for (active = iln; active; active = active->parent) {
-                                                                       if (callee == active->m) {
-                                                                               DOLOG( printf("RECURSIVE!\n") );
-                                                                               goto dont_inline;
-                                                                       }
-                                                               }
-                                               
-                                                               calleenode = DNEW(inline_node);
-                                                               memset(calleenode,0,sizeof(inline_node));
-                                                               
-                                                               calleenode->ctx = iln->ctx;
-                                                               calleenode->m = callee;
-                                                               calleenode->synchronize = (callee->flags & ACC_SYNCHRONIZED);
-                                                               isstatic = (callee->flags & ACC_STATIC);
-
-                                                               if (!inline_jit_compile(calleenode))
-                                                                       return false;
-                                                               
-                                                               /* info about the call site */
-                                                               calleenode->depth = iln->depth+1;
-                                                               calleenode->callerblock = bptr;
-                                                               calleenode->callerins = iptr;
-                                                               calleenode->callerpc = iptr - m->basicblocks->iinstr;
-                                                               calleenode->o_handlers = handlers;
-                                                               
-                                                               /* info about the callee */
-                                                               calleenode->localsoffset = iln->localsoffset + m->maxlocals;
-                                                               calleenode->prolog_instructioncount = callee->parseddesc->paramcount;
-                                                               calleenode->epilog_instructioncount = 0;
-                                                               calleenode->extra_instructioncount = 0;
-
-                                                               if (calleenode->synchronize) {
-                                                                       methoddesc         *md;
-                                                                       builtintable_entry *bte;
-                                                                       
-                                                                       /* and exception handler */
-                                                                       /* ALOAD, builtin_monitorexit, ATHROW */
-                                                                       calleenode->extra_instructioncount += 3;
-                                                                       /* stack elements used in handler */
-                                                                       iln->cumul_stackcount += 2;
-
-                                                                       /* exception table entries */
-                                                                       iln->cumul_exceptiontablelength += 1 + nhandlers;
-
-                                                                       bte = builtintable_get_internal(BUILTIN_monitorenter);
-                                                                       md = bte->md;
-                                                                       if (md->memuse > calleenode->regdata->memuse)
-                                                                               calleenode->regdata->memuse = md->memuse;
-                                                                       if (md->argintreguse > calleenode->regdata->argintreguse)
-                                                                               calleenode->regdata->argintreguse = md->argintreguse;
-
-                                                                       /* XXX
-                                                                       bte = builtintable_get_internal(BUILTIN_staticmonitorenter);
-                                                                       md = bte->md;
-                                                                       if (md->memuse > calleenode->regdata->memuse)
-                                                                               calleenode->regdata->memuse = md->memuse;
-                                                                       if (md->argintreguse > calleenode->regdata->argintreguse)
-                                                                               calleenode->regdata->argintreguse = md->argintreguse;
-                                                                               */
-
-                                                                       bte = builtintable_get_internal(BUILTIN_monitorexit);
-                                                                       md = bte->md;
-                                                                       if (md->memuse > calleenode->regdata->memuse)
-                                                                               calleenode->regdata->memuse = md->memuse;
-                                                                       if (md->argintreguse > calleenode->regdata->argintreguse)
-                                                                               calleenode->regdata->argintreguse = md->argintreguse;
-
-                                                                       iln->ctx->calls_others = true;
-                                                               }
-
-                                                               calleenode->stackcount = callee->stackcount;
-                                                               calleenode->cumul_stackcount = callee->stackcount;
-
-                                                               /* see how deep the stack is below the arguments */
-                                                               sp = o_curstack;
-                                                               for (i=0; sp; sp = sp->prev)
-                                                                       i++;
-                                                               calleenode->n_callerstackdepth = iln->n_callerstackdepth + i - callee->parseddesc->paramcount;
-
-                                                               insert_inline_node(iln,calleenode);
-
-                                                               if (!inline_inline_intern(callee,jd,calleenode))
-                                                                       return false;
-
-                                                               if (calleenode->synchronize) {
-                                                                       /* add exception handler block */
-                                                                       iln->ctx->master->cumul_basicblockcount++;
-                                                               }
-
-                                                               iln->cumul_instructioncount += calleenode->prolog_instructioncount;
-                                                               iln->cumul_instructioncount += calleenode->epilog_instructioncount;
-                                                               iln->cumul_instructioncount += calleenode->extra_instructioncount;
-                                                               iln->cumul_instructioncount += calleenode->cumul_instructioncount - 1/*invoke*/ + 2 /*INLINE_START|END*/;
-                                                               iln->cumul_stackcount += calleenode->cumul_stackcount;
-
-                                                               /* XXX extra block after inlined call */
-                                                               iln->cumul_stackcount += calleenode->n_callerstackdepth;
-                                                               iln->cumul_basicblockcount += 1;
-                                                               
-                                                               iln->cumul_basicblockcount += calleenode->cumul_basicblockcount;
-                                                               iln->cumul_exceptiontablelength += calleenode->cumul_exceptiontablelength;
-                                                               if (calleenode->cumul_maxstack > iln->cumul_maxstack)
-                                                                       iln->cumul_maxstack = calleenode->cumul_maxstack;
-                                                               if (calleenode->cumul_maxlocals > iln->cumul_maxlocals)
-                                                                       iln->cumul_maxlocals = calleenode->cumul_maxlocals;
+                                       if (!INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                                               callee = iptr->sx.s23.s3.fmiref->p.method;
+
+#if 0
+                                               if (
+                                                       (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Code_Table") == 0
+                                                               && (strcmp(callee->name->text, "of") == 0
+                                                                || strcmp(callee->name->text, "set") == 0))
+                                                       ||
+                                                       (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Compressor") == 0
+                                                               && (strcmp(callee->name->text, "output") == 0))
+                                                       ||
+                                                       (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Decompressor") == 0
+                                                               && (strcmp(callee->name->text, "getcode") == 0))
+                                                       ||
+                                                       (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Output_Buffer") == 0
+                                                               && (strcmp(callee->name->text, "putbyte") == 0))
+                                                       ||
+                                                       (strcmp(callee->class->name->text, "spec/benchmarks/_201_compress/Input_Buffer") == 0
+                                                               && (strcmp(callee->name->text, "getbyte") == 0
+                                                                || strcmp(callee->name->text, "readbytes") == 0
+                                                                ))
+                                                       )
+                                                       goto force_inline;
+
+                                               if (callee->jcodelength > 0)
+                                                       goto dont_inline;
+#endif
+
+                                               if (callee->flags & ACC_NATIVE)
+                                                       goto dont_inline;
+
+                                               if (iln->depth >= 3)
+                                                       goto dont_inline;
+
+                                               if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
+                                                                       || opcode == ICMD_INVOKESPECIAL)) {
+                                                       speculative = false;
+                                                       goto maybe_inline;
+                                               }
+
+                                               if (callee->flags & ACC_METHOD_MONOMORPHIC) {
+                                                       /* XXX */
+                                                       if (0
+                                                               && strncmp(callee->class->name->text, "java/", 5) != 0
+                                                               && strncmp(callee->class->name->text, "gnu/", 4) != 0
+                                                          )
+                                                       {
+                                                               printf("SPECULATIVE INLINE: "); method_println(callee);
+                                                               speculative = true;
+                                                               goto maybe_inline;
+                                                       }
+                                               }
+
+                                               /* polymorphic call site */
+                                               goto dont_inline;
+
+maybe_inline:
+                                               for (active = iln; active; active = active->parent) {
+                                                       if (callee == active->m) {
+                                                               DOLOG( printf("RECURSIVE!\n") );
+                                                               goto dont_inline;
                                                        }
                                                }
+
+force_inline:
+                                               if (!inline_analyse_callee(iln, callee,
+                                                                       bptr,
+                                                                       iptr,
+                                                                       iln->instructioncount - len - 1 /* XXX ugly */,
+                                                                       handlers,
+                                                                       nhandlers))
+                                                       return false;
+
+                                               if (speculative)
+                                                       method_add_assumption_monomorphic(callee, iln->ctx->master->m);
                                        }
 dont_inline:
+                                       break;
 
+                               case ICMD_RETURN:
+                               case ICMD_IRETURN:
+                               case ICMD_ARETURN:
+                               case ICMD_LRETURN:
+                               case ICMD_FRETURN:
+                               case ICMD_DRETURN:
+                                       /* extra ICMD_MOVE may be necessary */
+                                       iln->cumul_instructioncount++;
                                        break;
                        }
-
-                       o_curstack = o_dst;
-                       ++iptr;
                }
 
                /* end of basic block */
-       }       
+       }
 
        return true;
 }
 
-static void inline_write_exception_handlers(inline_node *master,inline_node *iln)
-{
-       basicblock *n_bptr;
-       stackptr n_curstack;
-       instruction *n_ins;
-       inline_node *child;
-       builtintable_entry *bte;
-       
-       child = iln->children;
-       if (child) {
-               do {
-                       inline_write_exception_handlers(master,child);
-                       child = child->next;
-               } while (child != iln->children);
-       }
-
-       if (iln->synchronize) {
-               /* create the monitorexit handler */
-               n_bptr = create_block(master,NULL,NULL,1 /*XXX*/);
-               n_bptr->type = BBTYPE_EXH;
-               n_bptr->flags = BBFINISHED;
-
-               iln->handler_monitorexit = n_bptr;
-               
-               n_curstack = n_bptr->instack;
-
-               /* ACONST / ALOAD */
 
-               n_curstack = inline_new_stackslot(master,n_curstack,TYPE_ADR);
-               
-               n_ins = master->inlined_iinstr_cursor++;
-               if (iln->m->flags & ACC_STATIC) {
-                       n_ins->opc = ICMD_ACONST;
-                       n_ins->val.a = iln->m->class;
-                       n_ins->target = (void *) 0x02; /* XXX target used temporarily as flag */
-               }
-               else {
-                       n_ins->opc = ICMD_ALOAD;
-                       n_ins->op1 = iln->localsoffset; /* XXX */
-               }
-               n_ins->dst = n_curstack;
-               n_ins->line = 0;
+/* post processing ************************************************************/
 
-               /* MONITOREXIT */
+#define POSTPROCESS_SRC(varindex)  live[varindex]--
+#define POSTPROCESS_DST(varindex)  live[varindex]++
 
-               n_curstack = n_curstack->prev;
+#define POSTPROCESS_SRCOP(s)  POSTPROCESS_SRC(iptr->s.varindex)
+#define POSTPROCESS_DSTOP(d)  POSTPROCESS_DST(iptr->d.varindex)
 
-               bte = builtintable_get_internal(BUILTIN_monitorexit);
+#define MARKSAVED(varindex)  jd->var[varindex].flags |= SAVEDVAR
 
-               n_ins = master->inlined_iinstr_cursor++;
-               n_ins->opc = ICMD_BUILTIN;
-               n_ins->val.a = bte;
-               n_ins->dst = n_curstack;
-               n_ins->line = 0;
+#define MARK_ALL_SAVED                                               \
+    do {                                                             \
+        for (i=0; i<jd->vartop; ++i)                                 \
+            if (live[i])                                             \
+                MARKSAVED(i);                                        \
+    } while (0)
 
-               /* ATHROW */
-               
-               n_curstack = n_curstack->prev;
-               
-               n_ins = master->inlined_iinstr_cursor++;
-               n_ins->opc = ICMD_ATHROW;
-               n_ins->dst = n_curstack;
-               n_ins->line = 0;
+static void inline_post_process(jitdata *jd)
+{
+       basicblock *bptr;
+       instruction *iptr;
+       instruction *iend;
+       s4 i;
+       icmdtable_entry_t *icmdt;
+       s4 *live;
+       methoddesc *md;
+       builtintable_entry *bte;
 
-               /* close basic block */
+       /* reset the SAVEDVAR flag of all variables */
 
-               n_bptr->outstack = n_curstack;
-               n_bptr->outdepth = stack_depth(n_curstack); /* XXX */
-               n_bptr->icount = 3;
-       }
-}
+       for (i=0; i<jd->vartop; ++i)
+               jd->var[i].flags &= ~SAVEDVAR;
 
-static bool test_inlining(inline_node *iln,jitdata *jd,
-               methodinfo **resultmethod, jitdata **resultjd)
-{
-       instruction *n_ins;
-       stackptr n_stack;
-       basicblock *n_bb;
-       methodinfo *n_method;
-       exceptiontable *n_ext;
-       exceptiontable *prevext;
-       codegendata *n_cd;
-       registerdata *n_rd;
-       jitdata *n_jd;
-       
+       /* allocate the life counters */
 
-       static int debug_verify_inlined_code = 1;
-#ifndef NDEBUG
-       static int debug_compile_inlined_code_counter = 0;
-#endif
+       live = DMNEW(s4, jd->vartop);
+       MZERO(live, s4, jd->vartop);
 
-       assert(iln && jd && resultmethod && resultjd);
+       /* iterate over all basic blocks */
 
-       *resultmethod = iln->m;
-       *resultjd = jd;
+       for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
+               if (bptr->flags < BBREACHED)
+                       continue;
 
-#if 0
-       if (debug_compile_inlined_code_counter >5)
-               return false;
-#endif
+               /* make invars live */
 
-       n_ins = DMNEW(instruction,iln->cumul_instructioncount);
-       iln->inlined_iinstr = n_ins;
+               for (i=0; i<bptr->indepth; ++i)
+                       POSTPROCESS_DST(bptr->invars[i]);
 
-       n_stack = DMNEW(stackelement,iln->cumul_stackcount);
-       iln->n_inlined_stack = n_stack;
-       iln->ctx->n_debug_stackbase = n_stack;
+               iptr = bptr->iinstr;
+               iend = iptr + bptr->icount;
+
+               for (; iptr < iend; ++iptr) {
+
+                       icmdt = &(icmd_table[iptr->opc]);
+
+                       switch (icmdt->dataflow) {
+                               case DF_3_TO_0:
+                                       POSTPROCESS_SRCOP(sx.s23.s3);
+                               case DF_2_TO_0:
+                                       POSTPROCESS_SRCOP(sx.s23.s2);
+                               case DF_1_TO_0:
+                                       POSTPROCESS_SRCOP(s1);
+                               case DF_0_TO_0:
+                                       if (icmdt->flags & ICMDTABLE_CALLS) {
+                                               jd->isleafmethod = false;
+                                               MARK_ALL_SAVED;
+                                       }
+                                       break;
 
-       n_bb = DMNEW(basicblock,iln->cumul_basicblockcount);
-       iln->inlined_basicblocks = n_bb;
+                               case DF_2_TO_1:
+                                       POSTPROCESS_SRCOP(sx.s23.s2);
+                               case DF_1_TO_1:
+                               case DF_MOVE:
+                                       POSTPROCESS_SRCOP(s1);
+                               case DF_0_TO_1:
+                                       if (icmdt->flags & ICMDTABLE_CALLS) {
+                                               jd->isleafmethod = false;
+                                               MARK_ALL_SAVED;
+                                       }
+                               case DF_COPY:
+                                       POSTPROCESS_DSTOP(dst);
+                                       break;
 
-       iln->ctx->blockmap = DMNEW(inline_block_map,iln->cumul_basicblockcount);
+                               case DF_N_TO_1:
+                                       for (i=0; i<iptr->s1.argcount; ++i) {
+                                               POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
+                                       }
+                                       if (icmdt->flags & ICMDTABLE_CALLS) {
+                                               jd->isleafmethod = false;
+                                               MARK_ALL_SAVED;
+                                       }
+                                       POSTPROCESS_DSTOP(dst);
+                                       break;
 
-       rewrite_method(iln);
-       inline_write_exception_handlers(iln,iln);
+                               case DF_INVOKE:
+                                       INSTRUCTION_GET_METHODDESC(iptr, md);
+               post_process_call:
+                                       jd->isleafmethod = false;
+                                       for (i=0; i<md->paramcount; ++i) {
+                                               POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
+                                       }
+                                       for (; i<iptr->s1.argcount; ++i) {
+                                               MARKSAVED(iptr->sx.s23.s2.args[i]);
+                                       }
+                                       if (md->returntype.type != TYPE_VOID)
+                                               POSTPROCESS_DSTOP(dst);
+                                       break;
 
-       /* end of basic blocks */
-       if (iln->inlined_basicblocks_cursor > iln->inlined_basicblocks) {
-               iln->inlined_basicblocks_cursor[-1].next = NULL;
-       }
+                               case DF_BUILTIN:
+                                       bte = iptr->sx.s23.s3.bte;
+                                       md = bte->md;
+                                       goto post_process_call;
 
-       if (iln->cumul_exceptiontablelength) {
-               exceptiontable *tableend;
-               
-               n_ext = DMNEW(exceptiontable,iln->cumul_exceptiontablelength);
-               prevext = NULL;
-               tableend = inline_exception_tables(iln,n_ext,&prevext);
-               assert(tableend == n_ext + iln->cumul_exceptiontablelength);
-               if (prevext)
-                       prevext->down = NULL;
-       }
-       else {
-               n_ext = NULL;
-       }
+                               default:
+                                       assert(0);
+                       }
 
-       /*******************************************************************************/
+               } /* end instruction loop */
 
-       n_method = NEW(methodinfo);
-       memcpy(n_method,iln->m,sizeof(methodinfo));
-       n_method->maxstack = iln->cumul_maxstack; /* XXX put into cd,rd */
-       n_method->maxlocals = iln->cumul_maxlocals;
-       n_method->basicblockcount = iln->cumul_basicblockcount;
-       n_method->basicblocks = iln->inlined_basicblocks;
-       n_method->basicblockindex = NULL;
-       n_method->instructioncount = iln->cumul_instructioncount;
-       n_method->instructions = iln->inlined_iinstr;
-       n_method->stackcount = iln->cumul_stackcount;
-       n_method->stack = iln->n_inlined_stack;
-
-       n_method->exceptiontablelength = iln->cumul_exceptiontablelength;
-       n_method->exceptiontable = n_ext;
-       n_method->linenumbercount = 0;
-
-       n_jd = DNEW(jitdata);
-       n_jd->flags = 0;
-       n_jd->m = n_method;
-
-       if (iln->ctx->calls_others) {
-               n_method->isleafmethod = false;
-       }
-       
-       n_jd->code = code_codeinfo_new(n_method);
-
-       n_cd = DNEW(codegendata);
-       n_jd->cd = n_cd;
-       memcpy(n_cd,jd->cd,sizeof(codegendata));
-       n_cd->method = n_method;
-       n_cd->maxstack = n_method->maxstack;
-       n_cd->maxlocals = n_method->maxlocals;
-       n_jd->exceptiontablelength = n_method->exceptiontablelength;
-       n_jd->exceptiontable = n_method->exceptiontable;
-
-       n_rd = DNEW(registerdata);
-       n_jd->rd = n_rd;
-       reg_setup(n_jd);
+               /* consume outvars */
 
-       iln->regdata = jd->rd;
-       inline_locals(iln,n_rd);
-       DOLOG( printf("INLINING STACK INTERFACES FOR "); method_println(iln->m) );
-       inline_stack_interfaces(iln,n_rd);
-       
-#if defined(ENABLE_VERIFIER)
-       if (debug_verify_inlined_code) {
-               debug_verify_inlined_code = 0;
-               DOLOG( printf("VERIFYING INLINED RESULT...\n") );
-               if (!typecheck(n_jd)) {
-                       *exceptionptr = NULL;
-                       DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
-                       return false;
-               }
-               else {
-                       DOLOG( printf("VERIFICATION PASSED.\n") );
-               }
-               debug_verify_inlined_code = 1;
-       }
-#endif /* defined(ENABLE_VERIFIER) */
+               for (i=0; i<bptr->outdepth; ++i)
+                       POSTPROCESS_SRC(bptr->outvars[i]);
 
-#ifndef NDEBUG
-#if 1
-       if (n_method->instructioncount >= inline_debug_min_size && n_method->instructioncount <= inline_debug_max_size) {
-          if (debug_compile_inlined_code_counter >= inline_debug_start_counter 
-                          && debug_compile_inlined_code_counter <= inline_debug_end_counter) 
-#else
-       if (
-               (strcmp(n_method->class->name->text,"java/lang/reflect/Array") == 0 &&
-               strcmp(n_method->name->text,"<clinit>") == 0 &&
-               strcmp(n_method->descriptor->text,"()V") == 0)
-               ||
-               (strcmp(n_method->class->name->text,"java/lang/VMClassLoader") == 0 &&
-               strcmp(n_method->name->text,"getSystemClassLoader") == 0 &&
-               strcmp(n_method->descriptor->text,"()Ljava/lang/ClassLoader;") == 0)
-               ) 
-       
-       {
+#if !defined(NDEBUG)
+               for (i=jd->localcount; i < jd->vartop; ++i)
+                       assert(live[i] == 0);
 #endif
-#endif /* NDEBUG */
-          {
-                       *resultmethod = n_method;
-                       *resultjd = n_jd;
 
-#ifndef NDEBUG
-                       inline_count_methods++;
-                       if (inline_debug_log_names)
-                               method_println(n_method);
+       } /* end basic block loop */
+}
 
-                       DOLOG(
-                       printf("==== %d.INLINE ==================================================================\n",debug_compile_inlined_code_counter);
-                       method_println(n_method);
-                       show_method(jd);
-                       dump_inline_tree(iln);
-                       show_method(n_jd);
-                       debug_dump_inlined_code(iln,n_method,n_cd,n_rd);
-                       printf("-------- DONE -----------------------------------------------------------\n");
-                       fflush(stdout);
-                       );
-#endif
-          }
 
-#ifndef NDEBUG
-               debug_compile_inlined_code_counter++;
-       }
-#endif
-       return true;
-}
+/* main driver function *******************************************************/
 
-bool inline_inline(jitdata *jd, methodinfo **resultmethod, 
-                                  jitdata **resultjd)
+bool inline_inline(jitdata *jd, jitdata **resultjd)
 {
        inline_node *iln;
        methodinfo *m;
 
        m = jd->m;
 
-       *resultmethod = m;
        *resultjd = jd;
 
-#if 0
-       printf("==== INLINE ==================================================================\n");
-       method_println(m);
-       show_method(jd);
-#endif
-       
+       DOLOG( printf("==== INLINE ==================================================================\n");
+                  show_method(jd, SHOW_STACK); );
+
        iln = DNEW(inline_node);
-       memset(iln,0,sizeof(inline_node));
+       MZERO(iln, inline_node, 1);
 
-       iln->ctx = (inline_context *) DMNEW(u1,sizeof(inline_context) + sizeof(inline_stack_translation) * 1000 /* XXX */);
-       memset(iln->ctx,0,sizeof(inline_context));
+       iln->ctx = DNEW(inline_context);
+       MZERO(iln->ctx, inline_context, 1);
        iln->ctx->master = iln;
-       iln->ctx->stacktranslationstart = iln->ctx->stacktranslation - 1;
        iln->ctx->calls_others = false;
-       iln->m = m;             
+       iln->m = m;
+       iln->jd = jd;
+       iln->regdata = jd->rd;
+       iln->ctx->next_debugnr = 1; /* XXX debug */
+
+       iln->blockbefore = true;
+       iln->blockafter = true;
 
-       /* we cannot use m->instructioncount because it may be greater than 
+       /* we cannot use m->instructioncount because it may be greater than
         * the actual number of instructions in the basic blocks. */
        iln->instructioncount = 0;
        iln->cumul_instructioncount = 0;
+       iln->cumul_basicblockcount = 1 /* dummy end block */;
 
-       iln->stackcount = m->stackcount;
-       iln->cumul_stackcount = m->stackcount;
+       if (inline_inline_intern(m, iln)) {
 
-       if (inline_inline_intern(m,jd,iln)) {
-       
-#if 0
-               printf("==== TEST INLINE =============================================================\n");
-               method_println(m);
-#endif
+               DOLOG( printf("==== TEST INLINE =============================================================\n"); );
 
                if (iln->children)
-                       test_inlining(iln,jd,resultmethod,resultjd);
+                       test_inlining(iln, jd, resultjd);
        }
 
-#if 0
-       printf("-------- DONE -----------------------------------------------------------\n");
-       fflush(stdout);
-#endif
+       DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
+       fflush(stdout); );
 
        return true;
 }
index d77f1719a992fdfe98a9f9701b4554ea0044a7a3..20ff28ca7aa8c324c66a77a2b0f9ba58ff949a29 100644 (file)
@@ -1,69 +1,19 @@
-#include <ctype.h>
-
-#define DEBUG_SLOT(slot)  ((int)((slot) ? ((slot) - iln->ctx->n_debug_stackbase) : (-1)))
-
-#if 0
-               printf("linenumbertable_entry %p: pc=%p line=%08x, lntsize=%d, looking for pc=%p\n",
-                               (void*)lntentry,(void*)lntentry->pc,lntentry->line,lntsize,(void*)pc);
-#endif
-
-#if 0
-                                               printf("inline entry %p: pc=%p line=%08x, lntsize=%d, looking for pc=%p\n",
-                                                               (void*)lntinline,(void*)lntinline->pc,lntinline->line,lntsize,(void*)pc);
-                                               printf("\trecurse %p into %p ",(void*)lntinline,(void*)lntinline->pc); method_println((methodinfo *)lntinline->pc);
-#endif
-
-#if 0
-       if (oa) {
-           int i;
-
-           for (i=0; i<oa->header.size; ++i) {
-               printf("\t%i: %p ",i,(void*)oa->data[i]);
-               if (oa->data[i])
-                   class_println((classinfo *)oa->data[i]);
-               else
-                   printf("\n");
-           }
-       }
-       printf("GOT CLASS: %p\n",c);
-       if (c) {
-           class_println(c);
-       }
-       printf("GOT CLASSLOADER: %p\n",cl);
-       if (cl) {
-           class_println(cl->vftbl->class);
-       }
-#endif
-
 static void debug_dump_inline_context(inline_node *iln)
 {
-       inline_stack_translation *tr;
-       
-       printf("inline_context @%p: stackbase=%p transstart=%p translationlimit=%p\n",
-                       (void*)iln->ctx,(void*)iln->ctx->n_debug_stackbase,
-                       (void*)iln->ctx->stacktranslationstart,(void*)iln->ctx->o_translationlimit);
-       tr = iln->ctx->stacktranslationstart;
-       while (tr >= iln->ctx->stacktranslation) {
-               printf("\ttranslate %p -> %d (%p)\n",
-                               (void*)tr->o_sp,DEBUG_SLOT(tr->n_sp),(void*)tr->n_sp);
-               tr--;
-       }
-}
+       assert(iln->indent);
 
-static void debug_dump_stack(stackptr sp)
-{
-       while (sp) {
-               printf("%p (%d) (%01d:%02d:%01x) -> ",(void*)sp,sp->type,sp->varkind,sp->varnum,sp->flags);
-               sp = sp->prev;
-       }
-       printf("%p",(void*)NULL);
+       printf("%sinline_context @%p: \n",
+                       iln->indent, (void*)iln->ctx);
 }
 
-static void dump_inline_tree(inline_node *iln)
+
+static void dump_inline_tree(inline_node *iln, s4 blocknr)
 {
        char indent[100];
        int i;
        inline_node *child;
+       s4 nr;
+       s4 lastnr;
 
        if (!iln) {
                printf("(inline_node *)null\n");
@@ -80,187 +30,62 @@ static void dump_inline_tree(inline_node *iln)
                        printf("parent unset");
                }
                else {
-                       printf("%s[%d] L%03d %d-%d (ins %d,st %d) (sd=%d,cs=%p,lofs=%d) cum(ins %d,st %d,bb %d) ",
-                                       indent,iln->depth,iln->callerblock->debug_nr,
-                                       iln->callerpc,(int)(iln->callerblock->iinstr - iln->parent->m->basicblocks->iinstr),
-                                       iln->instructioncount,iln->stackcount,iln->n_callerstackdepth,
-                                       (void*)iln->n_callerstack,
+                       printf("%s[%d] (°%d) start L%03d %c%c (caller L%03d pc %d)"
+                                  " (ins %d) (pt=%d+%d,lofs=%d,exh %d) cum(ins %d,bb %d,etl %d) sync=%d(%d) ",
+                                       indent, iln->depth, iln->debugnr, blocknr,
+                                       (iln->blockbefore) ? 'B' : '-',
+                                       (iln->blockafter) ? 'A' : '-',
+                                       iln->callerblock->nr, iln->callerpc,
+                                       iln->instructioncount,
+                                       iln->n_passthroughcount - iln->n_selfpassthroughcount,
+                                       iln->n_selfpassthroughcount,
                                        iln->localsoffset,
-                                       iln->cumul_instructioncount,iln->cumul_stackcount,iln->cumul_basicblockcount);
+                                       iln->n_handlercount,
+                                       iln->cumul_instructioncount, iln->cumul_basicblockcount,
+                                       iln->cumul_exceptiontablelength,
+                                       iln->synchronize, iln->synclocal
+                                       );
                }
        }
        else {
-               printf("%s[%d] MAIN (ins %d,st %d) (cs=%p) cum(ins %d,st %d,bb %d) ",indent,iln->depth,
-                               iln->instructioncount,iln->stackcount,
-                               (void*)iln->n_callerstack,
-                               iln->cumul_instructioncount,iln->cumul_stackcount,iln->cumul_basicblockcount);
+               printf("%s[%d] ROOT (ins %d) cum(ins %d,bb %d,etl %d) ",
+                               indent, iln->depth,
+                               iln->instructioncount,
+                               iln->cumul_instructioncount, iln->cumul_basicblockcount,
+                               iln->cumul_exceptiontablelength);
        }
        method_println(iln->m);
 
        child = iln->children;
+       lastnr = 0;
+       nr = blocknr;
        if (child) {
                do {
-                       dump_inline_tree(child);
-               }
-               while ((child = child->next) != iln->children);
-       }
-}
+                       nr += (child->callerblock->nr - lastnr);
+                       lastnr = child->callerblock->nr;
 
+                       if (child->blockbefore)
+                               nr++;
 
+                       dump_inline_tree(child, nr);
 
-static stackptr first_stackslot_of_block(basicblock *block)
-{
-       int len;
-       instruction *iptr;
-       stackptr sp;
-       
-       assert(block);
-       if (block->instack)
-               return block->instack - (block->indepth-1);
-       
-       len = block->icount;
-       iptr = block->iinstr;
-       while (len--) {
-               if (iptr->dst) {
-                       sp = iptr->dst;
-                       while (sp->prev) {
-                               sp = sp->prev;
-                       }
-                       return sp;
+                       nr += child->cumul_basicblockcount - 1;
+                       if (!child->blockbefore)
+                               nr++;
+                       if (child->blockafter)
+                               nr++;
                }
-               iptr++;
+               while ((child = child->next) != iln->children);
        }
 
-       return NULL;
-}
-
-static void debug_print_stack(inline_node *iln,stackptr sp,int validstackmin,int validstackmax)
-{
-       int i;
-       int idx;
-       char typechar;
-       char kindchar;
-       
-       printf("[");
-       for (i=0; i<iln->cumul_maxstack; ++i) {
-               if (sp) {
-                       idx = sp - iln->n_inlined_stack;
-                       switch (sp->type) {
-                               case TYPE_ADR: typechar = 'a'; break;
-                               case TYPE_INT: typechar = 'i'; break;
-                               case TYPE_LNG: typechar = 'l'; break;
-                               case TYPE_FLT: typechar = 'f'; break;
-                               case TYPE_DBL: typechar = 'd'; break;
-                               default:       typechar = '?';
-                       }
-            switch (sp->varkind) {
-                case STACKVAR: kindchar = 's'; break;
-                case LOCALVAR: kindchar = 'l'; break;
-                case TEMPVAR : kindchar = 't'; break;
-                case UNDEFVAR: kindchar = 'u'; break;
-                case ARGVAR  : kindchar = 'a'; break;
-                default:       kindchar = '_'; break;
-            }
-            if (sp->flags & SAVEDVAR)
-                kindchar = toupper(kindchar);
-                       printf("%c%-3d(%c%-2d:%01x) ",typechar,idx,kindchar,sp->varnum,sp->flags);
-                       sp = sp->prev;
-
-                       assert(idx >= validstackmin);
-                       assert(idx <= validstackmax);
-#if 0
-                       if (idx < validstackmin || idx > validstackmax) {
-                               printf("INVALID STACK INDEX: %d\n",idx);
-                       }
-#endif
-               }
-               else {
-                       printf("----        ");
-               }
+       if (iln->depth) {
+               printf("%s[%d] (°%d) end   L%03d\n",
+                               indent, iln->depth, iln->debugnr,
+                               blocknr + iln->cumul_basicblockcount
+                                               - ((iln->blockbefore) ? 1 : 0));
        }
-       printf("] ");
 }
 
-static void debug_dump_inlined_code(inline_node *iln,methodinfo *newmethod,codegendata *cd,registerdata *rd)
-{
-       basicblock *bptr;
-       instruction *iptr;
-       stackptr curstack;
-       stackptr dst;
-       basicblock *nextblock;
-       int len;
-       int validstackmin;
-       int validstackmax;
-       int i;
-       int type;
-
-       printf("INLINED CODE: maxstack=%d maxlocals=%d leafmethod=%d\n",
-                       newmethod->maxstack,newmethod->maxlocals,newmethod->isleafmethod);
-
-       for (i=0; i<newmethod->maxlocals; ++i) {
-           for (type=0; type<5; ++type) {
-               if (rd->locals[i][type].type < 0)
-                   continue;
-               printf("\tlocal %d type %d: flags %01x\n",i,type,rd->locals[i][type].flags);
-           }
-       }
-
-       for (i=0; i<newmethod->maxstack; ++i) {
-           for (type=0; type<5; ++type) {
-               if (rd->interfaces[i][type].type < 0)
-                   continue;
-               printf("\tinterface %d type %d: flags %01x\n",i,type,rd->interfaces[i][type].flags);
-           }
-       }
-
-       printf("registerdata:\n");
-       printf("\tmemuse = %d\n",rd->memuse);
-       printf("\targintreguse = %d\n",rd->argintreguse);
-       printf("\targfltreguse = %d\n",rd->argfltreguse);
-
-       validstackmin = 0;
 
-       bptr = iln->inlined_basicblocks;
-       for (; bptr; bptr = bptr->next) {
-               curstack = bptr->instack;
-               iptr = bptr->iinstr;
-               len = bptr->icount;
-
-               nextblock = bptr->next;
-find_stackmax:
-               if (nextblock) {
-                       dst = first_stackslot_of_block(nextblock);
-                       if (dst) {
-                               validstackmax = (dst - iln->n_inlined_stack) - 1;
-                       }
-                       else {
-                               nextblock = nextblock->next;
-                               goto find_stackmax;
-                       }
-               }
-               else {
-                       validstackmax = 10000; /* XXX */
-               }
-
-               debug_print_stack(iln,curstack,validstackmin,validstackmax);
-               printf("L%03d BLOCK %p indepth=%d outdepth=%d icount=%d stack=[%d,%d] type=%d flags=%d\n",
-                               bptr->debug_nr,(void*)bptr,bptr->indepth,bptr->outdepth,bptr->icount,
-                               validstackmin,validstackmax,
-                bptr->type,bptr->flags);
-
-               while (len--) {
-                       dst = iptr->dst;
-
-                       debug_print_stack(iln,dst,validstackmin,validstackmax);
-                       printf("     ");
-                       show_icmd(iptr,false); printf("\n");
-
-                       curstack = dst;
-                       iptr++;
-               }
-               printf("\n");
-
-               /* next basic block */
-               validstackmin = validstackmax + 1;
-       }
-}
+/* vim:noexpandtab:sw=4:ts=4:ft=c:
+ */