* Updated header: Added 2006. Changed address of FSF. Changed email
[cacao.git] / src / vm / jit / inline / inline.c
index 091745af75809b9e8d4a781b1eeda2a11b7d596b..6ca958d0a972fc5a4e9d9622a79508e36107db68 100644 (file)
-static void descriptor2types (methodinfo *m);
-
-/*typedef struct {
-        listnode linkage;
-        instruction *iptr;
-        } t_patchlistnode;*/
-
-
-typedef struct {
-        listnode linkage;
-
-        methodinfo *method;
-        int startgp;
-        int stopgp;
-        int firstlocal;
-
-        bool *readonly;
-        int  *label_index;
-        
-        list *inlinedmethods;
-} inlining_methodinfo;
-
-typedef struct {
-        listnode linkage;
-        
-       // saved static compiler variables
-        
-        methodinfo *method;
-        
-       // restored through method
-
-       // int jcodelength;
-       // u1 *jcode;
-       // classinfo *class;
-
-       // descriptor never used
-       // maxstack used outside of main for loop
-       // maxlocals never used
-       
-       // exceptiontablelength
-       // raw_extable used outside of main for loop
-       // mreturntype used outside of main for loop
-       // mparamcount used outside of main for loop
-       // mparamtypes used outside of main for loop
-
-       //local variables used in parse()  
+/* src/vm/jit/inline/inline.c - code inliner
+
+   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+   J. Wenninger, Institut f. Computersprachen - TU Wien
+
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Dieter Thuernbeck
+
+   Changes: Christian Thalinger
+
+   $Id: inline.c 4357 2006-01-22 23:33:38Z twisti $
+
+*/
+
+/*---
+Inlining initializes an inline structure with values of the method called
+with. Then it recursively to MAXDEPTH analyzes by parsing the bytecode 
+looking for methods that meet the critera to be inlined.
+
+Critera for inlining currently is:
+Method to be inlined must:
+- be less than MAXCODESIZE 
+- only MAXMETHODS can be inlined in 1 method
+
+-in only STATIC, FINAL, PRIVATE methods can be inlined from method's class
+-ino (include outsiders) all STATIC, FINAL, PRIVATE methods can be inlined
+       note: PRIVATE is always only in the same class
+-inv include virtual methods which static analysis (currently only RTA)
+     to only have 1 definition used (INVOKEVIRTUAL/INVOKEINTERFACE)
+     Currently dynamic loading is handled by rerunning with info 
+       (see parseRT). Guards need to be added.
+-inp  inline parameters - Parameters are analysed if they are
+       readonly, which is used during parsing to generate ICMD_CLEAR_ARGREN
+        and ICMD_CLEAR_ARGREN is in turn used during stack analysis to
+        replace the ISTORE with a NOP so the same local variable is used.
+       Parameters are pushed on the stack, same as normal method 
+       invocation when popped the local variable of calling program is used.
+-ine  JOWENN <- please add
+---*/
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mm/memory.h"
+#include "toolbox/logging.h"
+#include "vm/global.h"
+#include "vm/linker.h"
+#include "vm/loader.h"
+#include "vm/options.h"
+#include "vm/resolve.h"
+#include "vm/statistics.h"
+#include "vm/jit/jit.h"
+#include "vm/jit/parse.h"
+#include "vm/jit/inline/inline.h"
+
+#undef  INVIRTDEBUG  /* prints if a method was found to be 
+                        a unique virt/interface method  definition */
+#undef DEBUGi 
+
+#define METHINFOj(mm) \
+    { \
+        printf("<j%i/l%i/s%i/(p)%i>\t", \
+                (mm)->jcodelength,(mm)->maxlocals, \
+               (mm)->maxstack, (mm)->paramcount);  \
+        method_println(mm); }
+
+#define METHINFOx(mm) \
+    { \
+        printf("<c%i/m%i/p%i>\t", \
+                (mm)->class->classUsed,(mm)->methodUsed, (mm)->monoPoly); \
+        method_println(mm); }
+
+#define METHINFO(m) \
+  method_println(m); 
+
+#define IMETHINFO(m) \
+  utf_display(m->class->name); printf("."); fflush(stdout); \
+  method_println(m); fflush(stdout); \
+  printf("\tm->jcodelength=%i; ",m->jcodelength); fflush(stdout); \
+  printf("m->jcode=%p;\n",m->jcode); fflush(stdout); \
+  printf("\tm->maxlocals=%i; ",m->maxlocals); fflush(stdout); \
+  printf("m->maxstack=%i;\n",m->maxstack); fflush(stdout);
+
+/* checked functions and macros: LOADCONST code_get OP1 BUILTIN block_insert bound_check ALIGN */
+
+/* replace jcodelength loops with correct number after main for loop in parse()! */
+
+#define CLASSINFO(cls) \
+        {       printf("<c%i>\t",cls->classUsed); \
+                utf_display(cls->name); printf("\n");fflush(stdout);}
+
+static bool in_stats1 = true;
+/*-----------------------------------------------------------*/
+/* just initialize global structure for non-inlining         */
+/*-----------------------------------------------------------*/
+
+void inlining_init0(methodinfo *m, t_inlining_globals *inline_env)
+{
+       /* initialization for normal use in parse */
+       inlining_set_compiler_variables_fun(m, inline_env);
+       inline_env->isinlinedmethod = 0;
+       inline_env->cumjcodelength = m->jcodelength; /* for not inlining */
+
+       inline_env->cummaxstack = m->maxstack; 
+       inline_env->cumextablelength = 0;
+       inline_env->cumlocals = m->maxlocals;
+       inline_env->cummethods = 0; /* co not global or static-used only here? */
+       inline_env->inlining_stack = NULL;
+       inline_env->inlining_rootinfo = NULL;
+
+#if defined(ENABLE_STATISTICS)
+       if (in_stats1) {
+               int ii;
+               for (ii=0; ii<512; ii++) count_in_not[ii]=0;
+               in_stats1=false;
+               }
+#endif
+}
 
-       int  i;                     /* temporary for different uses (counters)    */
-       int  p;                     /* java instruction counter                   */
-       int  nextp;                 /* start of next java instruction             */
-       int  opcode;                /* java opcode                                */
 
-       inlining_methodinfo *inlinfo;
+/*-----------------------------------------------------------*/
 
-       /*      list *patchlist; */
-} t_inlining_stacknode;
+void inlining_setup(methodinfo *m, t_inlining_globals *inline_env)
+{
 
-// checked functions and macros: LOADCONST code_get OP1 BUILTIN block_insert bound_check ALIGN
+/*     t_inlining_globals *inline_env = DNEW(t_inlining_globals); */
+        inlining_init0(m,inline_env);
 
-// replace jcodelength loops with correct number after main for loop in parse()!
+if (useinlining)
+        {
+               #ifdef DEBUGi
+               printf("\n-------- Inlining init for: "); fflush(stdout);
+               IMETHINFO(m)
+               #endif
+               
+        inline_env->cumjcodelength = 0;
+        inline_env->inlining_stack = NEW(list);
+        list_init(inline_env->inlining_stack, 
+                 OFFSET(t_inlining_stacknode, linkage));
+        /*------ analyze ------*/
+        inline_env->inlining_rootinfo 
+               = inlining_analyse_method(m, 0, 0, 0, 0, inline_env);
+               #ifdef DEBUGi
+                       printf ("\n------------------------------ ");fflush(stdout);
+                       printf ("\nComplete Result of inlining analysis of:");
+                       fflush(stdout);
+                       METHINFOj(m)
+                       print_t_inlining_globals(inline_env); /* init ok */
+               #endif
+        /*---------------------*/
+/*
+ if (inline_env->cummethods == 0) {
+        inline_env = DNEW(t_inlining_globals);
+        inlining_init0(m,inline_env);
+        return inline_env;
+ }
+*/
+#if 0
+               #ifdef DEBUGi
+  printf("(l,s) (%i,%i) was (%i,%i)\n",
+    m->maxlocals, inline_env->cumlocals,
+    m->maxstack,  inline_env->cummaxstack); fflush(stdout);
+               #endif
+/*This looks wrong*/
+/* OK since other changes were also made, but in parse same stmt still */
+        m->maxlocals = inline_env->cumlocals;   orig not used
+        m->maxstack = inline_env->cummaxstack;  orig global maxstack var!!
+#endif
+        }
+}
 
-static list *inlining_stack;
-//static list *inlining_patchlist;
-static bool isinlinedmethod;
-static int cumjcodelength;         /* cumulative immediate intruction length      */
-static int cumlocals;
-static int cummaxstack;
-static int cumextablelength;
-static int cummethods;
-static inlining_methodinfo *inlining_rootinfo;
 
+void inlining_cleanup(t_inlining_globals *inline_env)
+{
+       FREE(inline_env->inlining_stack, t_inlining_stacknode);
+}
 
-void inlining_push_compiler_variables(int i, int p, int nextp, int opcode, inlining_methodinfo* inlinfo);
-void inlining_pop_compiler_variables(int *i, int *p, int *nextp, int *opcode, inlining_methodinfo** inlinfo); 
-void inlining_init(void);
-inlining_methodinfo *inlining_analyse_method(methodinfo *m, int level, int gp, int firstlocal, int maxstackdepth);
 
-#define inlining_save_compiler_variables() inlining_push_compiler_variables(i,p,nextp,opcode,inlinfo)
-#define inlining_restore_compiler_variables() inlining_pop_compiler_variables(&i,&p,&nextp,&opcode,&inlinfo)
-#define inlining_set_compiler_variables(i) p=nextp=0; inlining_set_compiler_variables_fun(i->method); inlinfo=i;
-#define INLINING_MAXDEPTH 1
-#define INLINING_MAXCODESIZE 32
-#define INLINING_MAXMETHODS 8
+/*--2 push the compile variables to save the method's environment --*/
 
-void inlining_init(void) 
+void inlining_push_compiler_variablesT(int opcode, inlining_methodinfo *inlinfo, t_inlining_globals *inline_env)
 {
-       inlining_stack = NULL;
-       //      inlining_patchlist = NULL;
-       isinlinedmethod = 0;
-       cumjcodelength = 0;
-       cumlocals = 0;
-       cumextablelength = 0;
-       cummaxstack = 0;
-       cummethods = 0;
-
-       inlining_stack = NEW(list);
-       list_init(inlining_stack, OFFSET(t_inlining_stacknode, linkage));
-       
-       inlining_rootinfo = inlining_analyse_method(method, 0, 0, 0, 0);
-       maxlocals = cumlocals;
-       maxstack = cummaxstack;
-}
+       t_inlining_stacknode *new = NEW(t_inlining_stacknode);
 
-void inlining_cleanup(void)
-{
-       FREE(inlining_stack, t_inlining_stacknode);
+       /**new->opcode = opcode; **/
+       new->method = inline_env->method;
+       new->inlinfo = inlinfo;
+       list_addfirst(inline_env->inlining_stack, new);
+       inline_env->isinlinedmethod++;
 }
+/*-- push the compile variables to save the method's environment --*/
 
-void inlining_push_compiler_variables(int i, int p, int nextp, int opcode, inlining_methodinfo *inlinfo) 
+void inlining_push_compiler_variables(int i, int p, int nextp, int opcode,  u2 lineindex,u2 currentline,u2 linepcchange,inlining_methodinfo *inlinfo, t_inlining_globals *inline_env)
 {
        t_inlining_stacknode *new = NEW(t_inlining_stacknode);
 
@@ -114,159 +220,374 @@ void inlining_push_compiler_variables(int i, int p, int nextp, int opcode, inlin
        new->p = p;
        new->nextp = nextp;
        new->opcode = opcode;
-       new->method = method;
-       //      new->patchlist = inlining_patchlist;
+       new->method = inline_env->method;
+       new->lineindex=lineindex;
+       new->currentline=currentline;
+       new->linepcchange=linepcchange;
        new->inlinfo = inlinfo;
-       
-       list_addfirst(inlining_stack, new);
-       isinlinedmethod++;
+       list_addfirst(inline_env->inlining_stack, new);
+       inline_env->isinlinedmethod++;
 }
 
-void inlining_pop_compiler_variables(int *i, int *p, int *nextp, int *opcode, inlining_methodinfo **inlinfo) 
+
+void inlining_pop_compiler_variables(
+                                    int *i, int *p, int *nextp,
+                                   int *opcode, u2 *lineindex,
+                                   u2 *currentline,u2 *linepcchange,
+                                    inlining_methodinfo **inlinfo,
+                                    t_inlining_globals *inline_env)
 {
-       t_inlining_stacknode *tmp = (t_inlining_stacknode *) list_first(inlining_stack);
+       t_inlining_stacknode *tmp 
+         = (t_inlining_stacknode *) list_first(inline_env->inlining_stack);
 
-       if (!isinlinedmethod) panic("Attempting to pop from inlining stack in toplevel method!\n");
+       if (!inline_env->isinlinedmethod) {
+               log_text("Attempting to pop from inlining stack in toplevel method!");
+               assert(0);
+       }
 
        *i = tmp->i;
        *p = tmp->p;
        *nextp = tmp->nextp;
        *opcode = tmp->opcode;
+
+       *lineindex=tmp->lineindex;
+       *currentline=tmp->currentline;
+       *currentline=tmp->linepcchange;
+
        *inlinfo = tmp->inlinfo;
 
-       method = tmp->method;
-       class = method->class;
-       jcodelength = method->jcodelength;
-       jcode = method->jcode;
-       //      inlining_patchlist = tmp->patchlist;
+        inline_env->method = tmp->method; /*co*/
+        inline_env->class = inline_env->method->class; /*co*/
+        inline_env->jcodelength = inline_env->method->jcodelength; /*co*/
+        inline_env->jcode = inline_env->method->jcode; /*co*/
 
-       list_remove(inlining_stack, tmp);
-       FREE(tmp, t_inlining_stacknode);
-       isinlinedmethod--;
+        list_remove(inline_env->inlining_stack, tmp);
+        FREE(tmp, t_inlining_stacknode);
+        inline_env->isinlinedmethod--;
 }
 
-void inlining_set_compiler_variables_fun(methodinfo *m)
+
+void inlining_set_compiler_variables_fun(methodinfo *m,
+                                        t_inlining_globals *inline_env)
 {
-       method = m;
-       class = m->class;
-       jcodelength = m->jcodelength;
-       jcode = m->jcode;
-       
-       //      inlining_patchlist = DNEW(list);
-       //      list_init(inlining_patchlist, OFFSET(t_patchlistnode, linkage));
+        inline_env->method = m; 
+        inline_env->class  = m->class; 
+        inline_env->jcode  = m->jcode; 
+        inline_env->jcodelength = m->jcodelength; 
 }
 
-/*void inlining_addpatch(instruction *iptr)  
-  {
-  t_patchlistnode *patch = DNEW(t_patchlistnode);
-  patch->iptr = iptr;
-  list_addlast(inlining_patchlist, patch);
-  }*/
+/* is_unique_method2 - determines if m is a unique method by looking
+       in subclasses of class that define method m 
+       It counts as it goes. It also saves the method name if found.
+
+ returns count of # methods used up to 2
+                               (since if 2 used then not unique.)
+                      sets mout to method found 
+                               (unique in class' heirarchy)
+                       It looks for subclasses with method def'd.
+ Input:
+ * class - where looking for method
+ * m     - original method ptr
+ * mout  - unique method (output) 
+ Output: "cnt" of methods found up to max of 2 (then not unique)
+*/
+
+int is_unique_method2(classinfo *class, methodinfo *m, methodinfo **mout)
+{
+utf* name = m->name;
+utf* desc = m->descriptor;
 
+int cnt = 0;  /* number of times method found in USED classes in hierarchy*/
+classinfo *subs1;         
 
-classinfo *first_occurence(classinfo* class, utf* name, utf* desc) {
-       classinfo *first = class;
-       
-       for (; class->super != NULL ; class = class->super) {
-               if (class_findmethod(class->super, name, desc) != NULL) {
-                       first = class->super;
-               }                       
+if ((m->class == class) && (class->classUsed == USED)) {
+       /* found method in current class, which is used */
+       if (*mout != m) {
+               cnt++;
+               *mout = m;
+               }
        }
-               return first;
-}
 
-bool is_unique_rec(classinfo *class, methodinfo *m, utf* name, utf* desc) {
-       methodinfo *tmp = class_findmethod(class, name, desc);
-       if ((tmp != NULL) && (tmp != m))
-               return false;
-
-       for (; class != NULL; class = class->nextsub) {
-               if ((class->sub != NULL) && !is_unique_rec(class->sub, m, name, desc)) {
-                       return false; 
+if ( ((m->flags & ACC_FINAL)  
+||    (class->sub == NULL))
+&& (class->classUsed == USED)) {
+       /* if final search no further */
+       if (*mout != m) {
+               cnt++;
+               *mout = m;
                }
+        return cnt;
        }
-       return true;
+
+/* search for the method in its subclasses */
+for (subs1 = class->sub;subs1 != NULL;subs1 = subs1->nextsub) {
+        methodinfo * sm;
+       classinfo *subs = subs1;           
+        sm = class_resolveclassmethod(subs,name,desc,class,false);
+        if (sm != NULL) {
+               if ((subs->classUsed == USED) && 
+                   (*mout != sm)) {
+                       *mout = sm;
+                       cnt++;
+                       }
+                cnt = cnt + is_unique_method2(subs, sm, mout);
+               /* Not unique if more than 1 def of method in class heir */
+                if (cnt > 1)
+                        {return cnt;}
+                }
+
+        }
+return cnt;
 }
 
-bool is_unique_method(classinfo *class, methodinfo *m, utf* name, utf* desc) {
-       classinfo *firstclass;
+/*-----------------------------------------------------------*/
+
+bool is_unique_interface_method (methodinfo *mi, methodinfo **mout) {
+
+utf* name = mi->name;
+utf* desc = mi->descriptor;
        
-       /*      sprintf (logtext, "First occurence of: ");
-       utf_sprint (logtext+strlen(logtext), m->class->name);
-       strcpy (logtext+strlen(logtext), ".");
-       utf_sprint (logtext+strlen(logtext), m->name);
-       utf_sprint (logtext+strlen(logtext), m->descriptor);
-       dolog (); */
+       classSetNode *classImplNode;
+       int icnt = 0;
+
+       for (classImplNode  = mi->class->impldBy;
+            classImplNode != NULL;                     
+            classImplNode  = classImplNode->nextClass) {
+
+               classinfo * classImplements = classImplNode->classType;
+               methodinfo *submeth;
+
+               submeth = class_findmethod(classImplements,name, desc); 
+               if (submeth != NULL) {
+                       icnt =+ is_unique_method2(
+                                   classImplements,
+                                   submeth,
+                                   mout);
+                       }       
+               if (icnt > 1) return false;
+               } /* end for*/
+if (icnt == 1) return true;
+else return false;
+} 
+
+/*-----------------------------------------------------------*/
+
+bool can_inline (
+       t_inlining_globals *inline_env,
+       methodinfo *m,
+       methodinfo *imi,
+       constant_FMIref *imr,
+       bool uniqueVirt,
+       int opcode)
        
-       firstclass = first_occurence(class, name, desc);
+/* options used inlinevirtual / uniqueVirt / inlineexctions  */
+{
+bool can = false;
+u2 whycannot = 0;
+if ((inline_env->cummethods < INLINING_MAXMETHODS) && 
+   /*** (!(imi->flags & ACC_ABSTRACT)) && ** Problem from INVOKE STATIC **/
+    (!(imi->flags & ACC_NATIVE)) &&
+    (inlineoutsiders || (m->class->name == imr->classref->name)) &&
+    (imi->jcodelength < INLINING_MAXCODESIZE) &&
+    (imi->jcodelength > 0) &&       /* FIXME: eliminate empty methods? also abstract??*/
+    (((!inlinevirtuals)  ||
+      (uniqueVirt     ))   ||
+     ((opcode != JAVA_INVOKEVIRTUAL) ||
+      (opcode != JAVA_INVOKEINTERFACE)) ) &&
+    (inlineexceptions || (imi->exceptiontablelength == 0)))  {
+#if defined(ENABLE_STATISTICS)
+       count_in++;
+       if (inlinevirtuals) { 
+               if   (opcode == JAVA_INVOKEVIRTUAL) {
+                       if (uniqueVirt)  count_in_uniqVirt++; 
+                       }
+               if   (opcode == JAVA_INVOKEINTERFACE) { 
+                       if (uniqueVirt)  count_in_uniqIntf++; 
+                       }
+               }
+#endif
+       can = true;
        
-       /*      sprintf (logtext, "\nis in class:");
-       utf_sprint (logtext+strlen(logtext), firstclass->name);
-       dolog (); */
-
-       if (firstclass != class) return false;
+       }
+else
+       can = false;
+/*------ inline statistics ------*/
+if ((!opt_stat) || can) return  can; 
+
+if (!can) {
+  bool mult = false;
+
+if  (imi->flags & ACC_NATIVE) return can; 
+if  (imi->flags & ACC_ABSTRACT) return can; 
+#if defined(ENABLE_STATISTICS)
+  count_in_rejected++;
+#endif
+                                               if (opt_verbose) 
+                                                       {char logtext[MAXLOGTEXT];
+                                                       sprintf(logtext, "Rejected to inline: ");
+                                                       utf_sprint(logtext  +strlen(logtext), imi->class->name);
+                                                       strcpy(logtext + strlen(logtext), ".");
+                                                       utf_sprint(logtext + strlen(logtext), imi->name);
+                                                       utf_sprint(logtext + strlen(logtext), imi->descriptor);
+                                                       log_text(logtext);
+                                                       METHINFOj(imi)
+                                                       }
+
+  if  (!(inlineoutsiders) && (m->class->name != imr->classref->name)) {
+       /*** if ((!mult) && (whycannot > 0)) mult = true;  *** First time not needed ***/
+#if defined(ENABLE_STATISTICS)
+       count_in_outsiders++;
+#endif
+       whycannot = whycannot | IN_OUTSIDERS; /* outsider */ 
+       }
+  if (inline_env->cummethods >= INLINING_MAXMETHODS) { 
+       if ((!mult) && (whycannot > 0)) mult = true; 
+#if defined(ENABLE_STATISTICS)
+       count_in_maxDepth++;
+#endif
+       whycannot = whycannot | IN_MAXDEPTH;  
+       }
+  if  (imi->jcodelength >= INLINING_MAXCODESIZE) {
+       if ((!mult) && (whycannot > 0)) mult = true;
+       whycannot = whycannot | IN_MAXCODE;  
+       }
+  if  (imi->jcodelength > 0) {
+       if ((!mult) && (whycannot > 0)) mult = true;
+       whycannot = whycannot | IN_JCODELENGTH;  
+       }
+  if  (!inlineexceptions && (imi->exceptiontablelength == 0)) { 
+       whycannot = whycannot | IN_EXCEPTION;  
+       }
+  /* These must be last so mult flag is set correctly */ 
+  if  ( (inlinevirtuals) && 
+       ((opcode == JAVA_INVOKEVIRTUAL) ||
+        (opcode == JAVA_INVOKEINTERFACE)) ) { 
+       if (uniqueVirt )   { 
+               /* so know why (and that) a unique virtual was rejected for another reason */ 
+               if (opcode == JAVA_INVOKEVIRTUAL) { 
+#if defined(ENABLE_STATISTICS)
+                       count_in_uniqueVirt_not_inlined++;
+#endif
+                       whycannot = whycannot | IN_UNIQUEVIRT;  
+                       }
+               else    {
+#if defined(ENABLE_STATISTICS)
+                       count_in_uniqueInterface_not_inlined++;
+#endif
+                       whycannot = whycannot | IN_UNIQUE_INTERFACE;  
+                       }
+               }       
+       else    { /* not inlined because not not virtual */
+               if ((!mult) && (whycannot > 0)) mult = true;
+               if (opcode == JAVA_INVOKEVIRTUAL) { 
+                       whycannot = whycannot | IN_NOT_UNIQUE_VIRT;  
+                       }
+               else    {
+                       whycannot = whycannot | IN_NOT_UNIQUE_INTERFACE;  
+                       }
+               }       
+       }       
+
+  if  (inlineoutsiders && (m->class->name != imr->classref->name)) {
+       whycannot = whycannot | IN_OUTSIDERS; /* outsider */ 
+#if defined(ENABLE_STATISTICS)
+       count_in_outsiders++;
+#endif
+       }
 
-       return is_unique_rec(class, m, name, desc);
+#if defined(ENABLE_STATISTICS)
+  if (mult)  
+       count_in_rejected_mult++;
+#endif
+  if (whycannot > ((1<<IN_MAX)-1)) {
+         log_text("Inline Whynot is too large???");
+         assert(0);
+  }
+#if defined(ENABLE_STATISTICS)
+  count_in_not[whycannot]++; 
+#endif
+  }
+
+return false;
 }
 
 
-inlining_methodinfo *inlining_analyse_method(methodinfo *m, int level, int gp, int firstlocal, int maxstackdepth)
+/*-----------------------------------------------------------*/
+
+
+inlining_methodinfo *inlining_analyse_method(methodinfo *m, 
+                                         int level, int gp, 
+                                         int firstlocal, int maxstackdepth,
+                                         t_inlining_globals *inline_env)
 {
        inlining_methodinfo *newnode = DNEW(inlining_methodinfo);
-       u1 *jcode = m->jcode;
+       /*u1 *jcode = m->jcode;*/
        int jcodelength = m->jcodelength;
        int p;
        int nextp;
        int opcode;
-       int i, lastlabel = 0;
+       int i=0;
        bool iswide = false, oldiswide;
        bool *readonly = NULL;
        int  *label_index = NULL;
        bool isnotrootlevel = (level > 0);
        bool isnotleaflevel = (level < INLINING_MAXDEPTH);
-
-       //      if (level == 0) gp = 0;
-       /*
-       sprintf (logtext, "Performing inlining analysis of: ");
-       utf_sprint (logtext+strlen(logtext), m->class->name);
-       strcpy (logtext+strlen(logtext), ".");
-       utf_sprint (logtext+strlen(logtext), m->name);
-       utf_sprint (logtext+strlen(logtext), m->descriptor);
-       dolog (); */
+       bool maxdepthHit = false;
+       #ifdef DEBUGi
+               printf ("\n------------------------------ ");fflush(stdout);
+               printf ("\nStart of inlining analysis of: ");fflush(stdout);
+               METHINFOj(m)
+               if (isnotrootlevel) printf(" isnotrootlevel=T ");
+               else printf(" isnotrootlevel=F ");
+               print_t_inlining_globals(inline_env); /* init ok */
+       #endif
+       #undef DEBUGi
+
+       /* if (level == 0) gp = 0; */
 
        if (isnotrootlevel) {
-               newnode->readonly = readonly = DMNEW(bool, m->maxlocals); //FIXME only paramcount entrys necessary
-               for (i = 0; i < m->maxlocals; readonly[i++] = true);
-               isnotrootlevel = true;
+               newnode->readonly = readonly = DMNEW(bool, m->maxlocals); /* FIXME only paramcount entrys necessary - ok FIXED also turned on*/
+
+               /** for (i = 0; i < m->maxlocals; readonly[i++] = true); **/
+               for (i = 0; i < m->paramcount; readonly[i++] = true);
+               /***isnotrootlevel = true; This had turned -inp off **/
+
        } else {
                readonly = NULL;
        }
        
-       label_index = DMNEW(int, jcodelength);
+       label_index = DMNEW(int, jcodelength+200);
 
        newnode->inlinedmethods = DNEW(list);
        list_init(newnode->inlinedmethods, OFFSET(inlining_methodinfo, linkage));
 
        newnode->method = m;
+       newnode->level = level;
        newnode->startgp = gp;
        newnode->readonly = readonly;
        newnode->label_index = label_index;
        newnode->firstlocal = firstlocal;
-       cumjcodelength += jcodelength + m->paramcount + 1 + 5;
-       if ((firstlocal + m->maxlocals) > cumlocals) cumlocals = firstlocal + m->maxlocals;
-       if ((maxstackdepth + m->maxstack) >  cummaxstack) cummaxstack = maxstackdepth + m->maxstack;
-       cumextablelength += m->exceptiontablelength;
+       inline_env->cumjcodelength += jcodelength + m->paramcount + 1 + 5;
+
+       if ((firstlocal + m->maxlocals) > inline_env->cumlocals) {
+               inline_env->cumlocals = firstlocal + m->maxlocals;
+       }
+
+       if ((maxstackdepth + m->maxstack) > inline_env->cummaxstack) {
+               inline_env->cummaxstack = maxstackdepth + m->maxstack;
+       }
+
+       inline_env->cumextablelength += m->exceptiontablelength;
    
 
        for (p = 0; p < jcodelength; gp += (nextp - p), p = nextp) {
-               opcode = code_get_u1 (p);
+               opcode = code_get_u1 (p,m);
                nextp = p + jcommandsize[opcode];
                oldiswide = iswide;
 
                /* figure out nextp */
 
                switch (opcode) {
-
                case JAVA_ILOAD:
                case JAVA_LLOAD:
                case JAVA_FLOAD:
@@ -280,12 +601,17 @@ inlining_methodinfo *inlining_analyse_method(methodinfo *m, int level, int gp, i
                case JAVA_ASTORE: 
 
                case JAVA_RET:
-
-                       if (iswide) { nextp = p + 3; iswide = false; }
+                       if (iswide) {
+                               nextp = p + 3;
+                               iswide = false;
+                       }
                        break;
 
                case JAVA_IINC:
-                       if (iswide) { nextp = p + 5; iswide = false; }
+                       if (iswide) {
+                               nextp = p + 5;
+                               iswide = false;
+                       }
                        break;
 
                case JAVA_WIDE:
@@ -295,31 +621,31 @@ inlining_methodinfo *inlining_analyse_method(methodinfo *m, int level, int gp, i
 
                case JAVA_LOOKUPSWITCH:
                        nextp = ALIGN((p + 1), 4) + 4;
-                       nextp += code_get_u4(nextp) * 8 + 4;
+                       nextp += code_get_u4(nextp,m) * 8 + 4;
                        break;
 
                case JAVA_TABLESWITCH:
                        nextp = ALIGN((p + 1), 4) + 4;
-                       nextp += (code_get_u4(nextp+4) - code_get_u4(nextp) + 1) * 4 + 4;
+                       nextp += (code_get_u4(nextp+4,m) - code_get_u4(nextp,m) + 1) * 4 + 4 +4;
                        break;
-
                }
+
                /* detect readonly variables in inlined methods */
                
                if (isnotrootlevel) { 
                        bool iswide = oldiswide;
                        
                        switch (opcode) {
-                               
                        case JAVA_ISTORE:
                        case JAVA_LSTORE:
                        case JAVA_FSTORE:
                        case JAVA_DSTORE:
                        case JAVA_ASTORE: 
-                               if (!iswide)
-                                       i = code_get_u1(p+1);
-                               else {
-                                       i = code_get_u2(p+1);
+                               if (!iswide) {
+                                       i = code_get_u1(p + 1,m);
+
+                               } else {
+                                       i = code_get_u2(p + 1,m);
                                }
                                readonly[i] = false;
                                break;
@@ -353,93 +679,335 @@ inlining_methodinfo *inlining_analyse_method(methodinfo *m, int level, int gp, i
                                break;
 
                        case JAVA_IINC:
-                               
                                if (!iswide) {
-                                       i = code_get_u1(p + 1);
-                               }
-                               else {
-                                       i = code_get_u2(p + 1);
+                                       i = code_get_u1(p + 1,m);
+
+                               else {
+                                       i = code_get_u2(p + 1,m);
                                }
                                readonly[i] = false;
                                break;
                        }
-                       
-                       
                }
 
                /*              for (i=lastlabel; i<=p; i++) label_index[i] = gp; 
-               //              printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
+                               printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
                lastlabel = p+1; */
-               for (i=p; i < nextp; i++) label_index[i] = gp;
-
+               for (i = p; i < nextp; i++) label_index[i] = gp;
+
+               if (opt_stat) { 
+                       if ((!isnotrootlevel) && !maxdepthHit) {
+                               maxdepthHit = true;
+#if defined(ENABLE_STATISTICS)
+                               count_in_maxDepth++;
+#endif
+                       }
+                       }
                if (isnotleaflevel) { 
 
                        switch (opcode) {
+
+                       case JAVA_INVOKEINTERFACE:
                        case JAVA_INVOKEVIRTUAL:
-                               if (!inlinevirtuals) break;
+                               if (!inlinevirtuals) 
+                                       break;
+                       
+                       case JAVA_INVOKESPECIAL:
                        case JAVA_INVOKESTATIC:
-                               i = code_get_u2(p + 1);
+                               i = code_get_u2(p + 1,m);
                                {
                                        constant_FMIref *imr;
                                        methodinfo *imi;
+                                       classinfo *imrclass;
 
-                                       imr = class_getconstant (m->class, i, CONSTANT_Methodref);
-                                       imi = class_findmethod (imr->class, imr->name, imr->descriptor);
+                                        methodinfo *mout;
+                                        bool uniqueVirt= false;
 
-                                       if (opcode == JAVA_INVOKEVIRTUAL) 
-                                               {
-                                                       if (!is_unique_method(imi->class, imi, imr->name ,imr->descriptor))
-                                                               break;
+
+                                       if (opcode ==JAVA_INVOKEINTERFACE) {
+                                           imr = class_getconstant(m->class, i, CONSTANT_InterfaceMethodref);
+                                               if (!imr)
+                                                       return NULL;
+                                               if (!resolve_classref(m,imr->classref,resolveEager,true, true,&imrclass)) {
+                                                       log_text("Could not resolve class reference");
+                                                       assert(0);
+                                               }
+                                           LAZYLOADING(imrclass)
+                                            imi = class_resolveinterfacemethod(
+                                               imrclass,
+                                                imr->name,
+                                                imr->descriptor,
+                                                m->class,
+                                                       true);
+                                           if (!imi) { /* extra for debug */
+                                                       log_text("ExceptionI thrown while parsing bytecode"); /* XXX should be passed on */
+                                                       assert(0);
+                                               }
+
+                                       } else {
+                                               imr = class_getconstant(m->class, i, CONSTANT_Methodref);
+                                               if (!imr)
+                                                       return NULL;
+                                               if (!resolve_classref(m,imr->classref,resolveEager,true, true,&imrclass)) {
+                                                       log_text("Could not resolve class reference");
+                                                       assert(0);
+                                               }
+                                          LAZYLOADING(imrclass)
+                                          imi = class_resolveclassmethod(
+                                               imrclass,
+                                               imr->name,
+                                               imr->descriptor,
+                                               m->class,
+                                               true);
+                                           if (!imi) { /* extra for debug */
+                                                       log_text("Exception0 thrown while parsing bytecode"); /* XXX should be passed on */
+                                                       assert(0);
                                                }
+                                           }
+
+                                       if (!imi) { /* normal-but never get here now */ 
+                                               log_text("Exception thrown while parsing bytecode"); /* XXX should be passed on */
+                                               assert(0);
+                                       }
+
+/** Inlining has problem currently with typecheck & inlining **/
+/** Due problem with typecheck & inlining, class checks fail for <init>s **/
+                                       if (utf_new_char("<init>") == imi->name) break; 
+                                       if (utf_new_char("finit$") == imi->name) break; 
+/****/                                 
+                                       if (opcode == JAVA_INVOKEVIRTUAL) {
+                                               mout = NULL;
+                                               /* unique virt meth? then */
+                                               /*  allow it to be inlined*/
+                                               if (is_unique_method2(imi->class, imi, &mout) == 1) {
+                                                  if (mout != NULL) {
+                                                        imi = mout;
+                                                        uniqueVirt=true; 
+#define INVIRTDEBUG
+#ifdef INVIRTDEBUG
+                                                       METHINFOx(imi);
+                                                        printf("WAS unique virtual(-iv)\n");fflush(stdout);
+#endif
+                                                        }
+                                                 } /* end is unique */
+                                               } /* end INVOKEVIRTUAL */       
+                                       if (opcode == JAVA_INVOKEINTERFACE){
+                                               mout = NULL; 
+#ifdef INVIRTDEBUG
+                                               METHINFOx(imi);
+#endif
+                                               if (is_unique_interface_method (imi,&mout)) {
+                                                     if (mout != NULL) {
+                                                        imi = mout;
+                                                        uniqueVirt=true;
+#ifdef INVIRTDEBUG
+                                                         METHINFOx(imi);
+                                                          printf("WAS unique interface(-iv)\n");fflush(stdout);
+#endif
+                                                        }
+                                                       
+                                                    } 
+                                               } /* end INVOKEINTERFACE */     
+
+                                       if (can_inline(inline_env, m, imi, imr, uniqueVirt, opcode)) {
+                                               inlining_methodinfo *tmp;
+                                               method_descriptor2types(imi);
+
+                                               inline_env->cummethods++;
+
+                                               if (opt_verbose) 
+                                                       {char logtext[MAXLOGTEXT];
+                                                       printf("Going to inline: ");
+                                                       METHINFOj(imi) 
+                                                       printf("\nFrom "); fflush(stdout); METHINFOj(m)
+                                                       sprintf(logtext, "Going to inline: ");
+                                                       utf_sprint(logtext  +strlen(logtext), imi->class->name);
+                                                       strcpy(logtext + strlen(logtext), ".");
+                                                       utf_sprint(logtext + strlen(logtext), imi->name);
+                                                       utf_sprint(logtext + strlen(logtext), imi->descriptor);
+                                                       log_text(logtext);
+                                                       sprintf(logtext,"<%i>",imi->jcodelength);
+                                                       log_text(logtext);
+                                                       if ( (!(opcode == JAVA_INVOKEVIRTUAL)) &&
+                                                            (! ( (imi->flags & ACC_STATIC )
+                                                            ||   ((imi->flags & ACC_PRIVATE) && (imi->class == inline_env->class))
+                                                            ||   (imi->flags & ACC_FINAL  ))) )
+                                                          {
+                                                          printf("DEBUG WARNING:PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n"); fflush(stdout);
+                                                          METHINFOx(imi);
+                                                          log_text("PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n See method info after DEBUG WARNING\n");
+                                                          }
 
-                                       if ( (cummethods < INLINING_MAXMETHODS) &&
-                                                (! (imi->flags & ACC_NATIVE)) &&  
-                                                ( !inlineoutsiders || (class == imr->class)) && 
-                                                (imi->jcodelength < INLINING_MAXCODESIZE) && 
-                                                (imi->jcodelength > 0) && 
-                                                (!inlineexceptions || (imi->exceptiontablelength == 0)) ) //FIXME: eliminate empty methods?
-                                               {
-                                                       inlining_methodinfo *tmp;
-                                                       descriptor2types(imi);
-
-                                                       cummethods++;
-
-                                                       /*      sprintf (logtext, "Going to inline: ");
-                                                       utf_sprint (logtext+strlen(logtext), imi->class->name);
-                                                       strcpy (logtext+strlen(logtext), ".");
-                                                       utf_sprint (logtext+strlen(logtext), imi->name);
-                                                       utf_sprint (logtext+strlen(logtext), imi->descriptor);
-                                                       dolog (); */
-
-                                                       tmp = inlining_analyse_method(imi, level+1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack);
-                                                       list_addlast(newnode->inlinedmethods, tmp);
-                                                       gp = tmp->stopgp;
-                                                       p = nextp;
                                                }
+                                               
+                                               tmp =inlining_analyse_method(imi, level + 1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack, inline_env);
+                                               list_addlast(newnode->inlinedmethods, tmp);
+               #ifdef DEBUGi
+printf("New node Right after an inline by:");fflush(stdout);
+METHINFOj(m)
+print_inlining_methodinfo(newnode);
+printf("end new node\n"); fflush(stdout);
+               #endif
+                                               gp = tmp->stopgp;
+                                               p = nextp;
+                                       }
                                }
                                break;
-                       default: 
                        }
                }  
-               
        } /* for */
        
        newnode->stopgp = gp;
+        label_index[jcodelength]=gp;
+    return newnode;
+}
 
-       /*
-       sprintf (logtext, "Result of inlining analysis of: ");
-       utf_sprint (logtext+strlen(logtext), m->class->name);
-       strcpy (logtext+strlen(logtext), ".");
-       utf_sprint (logtext+strlen(logtext), m->name);
-       utf_sprint (logtext+strlen(logtext), m->descriptor);
-       dolog ();
-       sprintf (logtext, "label_index[0..%d]->", jcodelength);
-       for (i=0; i<jcodelength; i++) sprintf (logtext, "%d:%d ", i, label_index[i]);
-       sprintf(logtext,"stopgp : %d\n",newnode->stopgp); */
+/* --------------------------------------------------------------------*/
+/*  print_ functions: check inline structures contain what is expected */
+/* --------------------------------------------------------------------*/
+void print_t_inlining_globals (t_inlining_globals *g) 
+{
+printf("\n------------\nt_inlining_globals struct for: \n\t");fflush(stdout); 
+METHINFOj(g->method);
+printf("\tclass=");fflush(stdout);
+  utf_display(g->class->name);printf("\n");fflush(stdout);
+
+printf("\tjcodelength=%i; jcode=%p;\n",g->jcodelength, g->jcode);
+
+if (g->isinlinedmethod==true) {
+  printf("\tisinlinedmethod=true ");fflush(stdout);  
+  }
+else {
+  printf("\tisinlinedmethod=false");fflush(stdout);  
+  }
+
+printf("\tcumjcodelength=%i ,cummaxstack=%i ,cumextablelength=%i ",
+ g->cumjcodelength,    g->cummaxstack,  g->cumextablelength);fflush(stdout);
+printf("\tcumlocals=%i ,cummethods=%i \n",
+ g->cumlocals,    g->cummethods);fflush(stdout);  
+
+printf("s>s>s> ");fflush(stdout);
+       print_inlining_stack     (g->inlining_stack);
+printf("i>i>i> "); fflush(stdout);
+       print_inlining_methodinfo(g->inlining_rootinfo);
+printf("-------------------\n");fflush(stdout);
+}
 
-    return newnode;
+/* --------------------------------------------------------------------*/
+void print_inlining_stack     ( list                *s)
+{
+  t_inlining_stacknode *is;
+
+if (s==NULL) { 
+  printf("\n\tinlining_stack: NULL\n");
+  return;
+  }
+
+/* print first  element to see if get into stack */
+printf("\n\tinlining_stack: NOT NULL\n");
+
+is=list_first(s); 
+if (is==NULL) { 
+    printf("\n\tinlining_stack = init'd but EMPTY\n");
+    fflush(stdout);
+    return;
+    }
+
+printf("\n\tinlining_stack: NOT NULL\n");
+
+for (is=list_first(s); 
+       is!=NULL;
+       is=list_next(s,is)) {
+        printf("\n\ti>--->inlining_stack entry: \n"); fflush(stdout);
+        METHINFOx(is->method);
+        printf("i=%i, p=%i, nextp=%i, opcode=%i;\n",
+               is->i,is->p,is->nextp,is->opcode);fflush(stdout);
+        print_inlining_methodinfo(is->inlinfo);
+    } /*end for */
 }
 
+/* --------------------------------------------------------------------*/
+void print_inlining_methodinfo( inlining_methodinfo *r) {
+  int i=0;
+  int cnt,cnt2;
+  inlining_methodinfo *im;
+  inlining_methodinfo *im2;
+  bool labellong = false;
+
+if (r==NULL) { 
+  printf("\n\tinlining_methodinfo: NULL\n");
+  return;
+  }
+printf("\n\tinlining_methodinfo for:"); fflush(stdout);
+
+if (r->method != NULL) {
+  utf_display(r->method->class->name); printf("."); fflush(stdout); \
+  method_println(r->method); fflush(stdout); \
+  }
+else {
+  printf(" NULL!!!!!\n");fflush(stdout);
+  }
+
+if (r->readonly==NULL) {
+  printf("\treadonly==NULL ");fflush(stdout);  
+  }
+else {
+  printf("\treadonly=");fflush(stdout);  
+  for (i = 0; i < r->method->maxlocals; i++)  {
+    if (r->readonly[i] == true)
+      printf("[i]=T;");
+    else
+      printf("[i]=F;");
+    fflush(stdout);
+    } 
+  }
+
+/**printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n", **/
+printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n",
+          r->startgp, r->stopgp, r->firstlocal, (void *)r->label_index);
+printf ("label_index[0..%d]->", r->method->jcodelength);
+if (labellong) {
+for (i=0; i<r->method->jcodelength; i++) printf ("%d:%d ", i, r->label_index[i]); }
+else {
+printf ("%d:%d ", 0, r->label_index[i]);
+printf ("%d:%d ", 
+  (r->method->jcodelength-1), r->label_index[r->method->jcodelength-1]);
+}
+
+printf("\n:::::inlines::::::::::::::::::::\n");
+if (list_first(r->inlinedmethods) == NULL) {
+       printf("Nothing\n");fflush(stdout);
+       }
+else {
+       for (im=list_first(r->inlinedmethods),cnt=0; 
+            im!=NULL;
+            im=list_next(r->inlinedmethods,im),cnt++) {
+               printf("*"); fflush(stdout);
+               printf("%i:",cnt);
+               printf("[1L%i] ",im->firstlocal); fflush(stdout);
+               METHINFOj(im->method)
+               printf("::::: which inlines::"); fflush(stdout);        
+               if (list_first(im->inlinedmethods) == NULL) {
+                       printf("Nothing\n");fflush(stdout);
+                       }
+               else   {
+                       printf("##"); fflush(stdout);
+                       for (im2=list_first(im->inlinedmethods),cnt2=0; 
+                            im2!=NULL;
+                            im2=list_next(im2->inlinedmethods,im2),cnt2++) 
+                               {
+                               printf("\t%i::",cnt2); fflush(stdout);
+                               printf("[1L%i] ",im2->firstlocal); 
+                                       fflush(stdout);
+                               METHINFOj(im2->method)
+                               }
+                       printf("\n"); fflush(stdout);
+                       }
+               } 
+      }
+}
+
+
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where
@@ -452,5 +1020,3 @@ inlining_methodinfo *inlining_analyse_method(methodinfo *m, int level, int gp, i
  * tab-width: 4
  * End:
  */
-
-