-/* jit/inline.c - code inliner
+/* src/vm/jit/inline/inline.c - code inliner
-globals moved to structure and passed as parameter
-
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
- M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
- P. Tomsich, J. Wenninger
+ 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.
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., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
- Contact: cacao@complang.tuwien.ac.at
+ Contact: cacao@cacaojvm.org
Authors: Dieter Thuernbeck
- $Id: inline.c 1429 2004-11-02 08:58:26Z jowenn $
+ 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 "global.h"
-#include "loader.h"
-#include "tables.h"
-#include "options.h"
-#include "jit/inline.h"
-#include "jit/jit.h"
-#include "jit/parse.h"
+
+#include "mm/memory.h"
#include "toolbox/logging.h"
-#include "toolbox/memory.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) \
- utf_display(m->class->name); printf("."); fflush(stdout); \
- method_display(m); fflush(stdout); \
+ method_println(m);
#define IMETHINFO(m) \
utf_display(m->class->name); printf("."); fflush(stdout); \
- method_display(m); 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);
-bool DEBUGi = false;
-// checked functions and macros: LOADCONST code_get OP1 BUILTIN block_insert bound_check ALIGN
+/* 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()! */
-// 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 */
/*-----------------------------------------------------------*/
-t_inlining_globals *inlining_init0(methodinfo *m,
- t_inlining_globals *inline_env)
+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;
+ /* 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; /*why has here been 0 ? */
- 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;
-return inline_env;
+
+ 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
}
+
+
/*-----------------------------------------------------------*/
-t_inlining_globals *inlining_init(methodinfo *m)
+void inlining_setup(methodinfo *m, t_inlining_globals *inline_env)
{
- t_inlining_globals *inline_env = DNEW(t_inlining_globals);
+
+/* t_inlining_globals *inline_env = DNEW(t_inlining_globals); */
inlining_init0(m,inline_env);
+
if (useinlining)
{
-if (DEBUGi==true) {
+ #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 ------*/
-if (DEBUGi==true) {print_t_inlining_globals(inline_env);}
inline_env->inlining_rootinfo
= inlining_analyse_method(m, 0, 0, 0, 0, inline_env);
-if (DEBUGi==true) {print_t_inlining_globals(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 (DEBUGi==true) {
+/*
+ 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);
- }
-#if 0
+ #endif
/*This looks wrong*/
- m->maxlocals = inline_env->cumlocals; //orig not used
- m->maxstack = inline_env->cummaxstack; //orig global maxstack var!!
+/* 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
-//panic("TEMP so can test just inline init\n");
}
-return inline_env;
}
}
+/*--2 push the compile variables to save the method's environment --*/
+
+void inlining_push_compiler_variablesT(int opcode, inlining_methodinfo *inlinfo, t_inlining_globals *inline_env)
+{
+ t_inlining_stacknode *new = NEW(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, u2 lineindex,u2 currentline,u2 linepcchange,inlining_methodinfo *inlinfo, t_inlining_globals *inline_env)
{
t_inlining_stacknode *new = NEW(t_inlining_stacknode);
t_inlining_stacknode *tmp
= (t_inlining_stacknode *) list_first(inline_env->inlining_stack);
- if (!inline_env->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;
void inlining_set_compiler_variables_fun(methodinfo *m,
t_inlining_globals *inline_env)
{
- /* XXX TWISTI */
- inline_env->method = m; /*co*/
- inline_env->class = m->class; /*co*/
- inline_env->jcode = m->jcode; /*co*/
- inline_env->jcodelength = m->jcodelength; /*co*/
+ inline_env->method = m;
+ inline_env->class = m->class;
+ inline_env->jcode = m->jcode;
+ inline_env->jcodelength = m->jcodelength;
}
+/* 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)
+*/
-classinfo *first_occurence(classinfo* class, utf* name, utf* desc)
+int is_unique_method2(classinfo *class, methodinfo *m, methodinfo **mout)
{
- classinfo *first = class;
-
- for (; class->super != NULL ; class = class->super) {
- if (class_findmethod(class->super, name, desc) != NULL) {
- first = class->super;
- }
- }
-
- return first;
-}
+utf* name = m->name;
+utf* desc = m->descriptor;
+int cnt = 0; /* number of times method found in USED classes in hierarchy*/
+classinfo *subs1;
-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;
+if ((m->class == class) && (class->classUsed == USED)) {
+ /* found method in current class, which is used */
+ if (*mout != m) {
+ cnt++;
+ *mout = m;
+ }
+ }
- 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 (); */
+ }
+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 (firstclass != class) return false;
+ if (inlineoutsiders && (m->class->name != imr->classref->name)) {
+ whycannot = whycannot | IN_OUTSIDERS; /* outsider */
+#if defined(ENABLE_STATISTICS)
+ count_in_outsiders++;
+#endif
+ }
+
+#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 is_unique_rec(class, m, name, desc);
+return false;
}
+
+/*-----------------------------------------------------------*/
+
+
inlining_methodinfo *inlining_analyse_method(methodinfo *m,
int level, int gp,
int firstlocal, int maxstackdepth,
int p;
int nextp;
int opcode;
- int i;
+ 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;
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;
case JAVA_TABLESWITCH:
nextp = ALIGN((p + 1), 4) + 4;
- nextp += (code_get_u4(nextp+4,m) - code_get_u4(nextp,m) + 1) * 4 + 4;
+ nextp += (code_get_u4(nextp+4,m) - code_get_u4(nextp,m) + 1) * 4 + 4 +4;
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;
+ 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)
+ if (!inlinevirtuals)
break;
+
+ case JAVA_INVOKESPECIAL:
case JAVA_INVOKESTATIC:
i = code_get_u2(p + 1,m);
{
constant_FMIref *imr;
methodinfo *imi;
+ classinfo *imrclass;
- imr = class_getconstant(m->class, i, CONSTANT_Methodref);
+ methodinfo *mout;
+ bool uniqueVirt= false;
- if (!class_load(imr->class))
- return NULL;
- if (!class_link(imr->class))
- return NULL;
+ 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);
+ }
- imi = class_resolveclassmethod(imr->class,
- imr->name,
- imr->descriptor,
- m->class,
- true);
+ } 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)
- panic("Exception thrown while parsing bytecode"); /* XXX should be passed on */
+ 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) {
- if (!is_unique_method(imi->class, imi, imr->name, imr->descriptor))
- break;
- }
+ 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 (imi->flags & ACC_NATIVE) log_text("Native method,no inlining"); //DEBUG
- if ((inline_env->cummethods < INLINING_MAXMETHODS) &&
- (!(imi->flags & ACC_NATIVE)) &&
- (!inlineoutsiders || (m->class == imr->class)) &&
- (imi->jcodelength < INLINING_MAXCODESIZE) &&
- (imi->jcodelength > 0) &&
- (!inlineexceptions || (imi->exceptiontablelength == 0))) { //FIXME: eliminate empty methods?
+ if (can_inline(inline_env, m, imi, imr, uniqueVirt, opcode)) {
inlining_methodinfo *tmp;
- descriptor2types(imi);
+ method_descriptor2types(imi);
inline_env->cummethods++;
- if (verbose) {
- char logtext[MAXLOGTEXT];
+ 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");
+ }
+
}
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;
}
} /* for */
newnode->stopgp = gp;
-
- if (DEBUGi==true) {
- printf ("\nResult of inlining analysis of: ");
- IMETHINFO(m);
- printf("was called by:\n"); fflush(stdout);
- IMETHINFO(inline_env->method);
- printf ("label_index[0..%d]->", jcodelength);
- for (i=0;i<jcodelength; i++) printf ("%d:%d ", i, label_index[i]);
- printf("stopgp : %d\n",newnode->stopgp);
- }
-
+ label_index[jcodelength]=gp;
return newnode;
}
void print_t_inlining_globals (t_inlining_globals *g)
{
printf("\n------------\nt_inlining_globals struct for: \n\t");fflush(stdout);
-METHINFO(g->method);
+METHINFOj(g->method);
printf("\tclass=");fflush(stdout);
utf_display(g->class->name);printf("\n");fflush(stdout);
g->cumlocals, g->cummethods);fflush(stdout);
printf("s>s>s> ");fflush(stdout);
-print_inlining_stack (g->inlining_stack);
+ print_inlining_stack (g->inlining_stack);
printf("i>i>i> "); fflush(stdout);
-print_inlining_methodinfo(g->inlining_rootinfo);
+ print_inlining_methodinfo(g->inlining_rootinfo);
printf("-------------------\n");fflush(stdout);
}
/* --------------------------------------------------------------------*/
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 */
- t_inlining_stacknode *is;
- printf("\n\tinlining_stack: NOT NULL\n");
- is=list_first(s);
- if (is==NULL) {
+/* 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;
}
- }
-
- {
- t_inlining_stacknode *is;
- printf("\n\tinlining_stack: NOT NULL\n");
+printf("\n\tinlining_stack: NOT NULL\n");
- for (is=list_first(s);
+for (is=list_first(s);
is!=NULL;
is=list_next(s,is)) {
printf("\n\ti>--->inlining_stack entry: \n"); fflush(stdout);
- METHINFO(is->method);
+ 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_display(r->method); fflush(stdout); \
+ method_println(r->method); fflush(stdout); \
}
else {
- printf("method is NULL!!!!!\n");fflush(stdout);
+ printf(" NULL!!!!!\n");fflush(stdout);
}
-printf("\n\tinlining_methodinfo for:"); fflush(stdout);
if (r->readonly==NULL) {
printf("\treadonly==NULL ");fflush(stdout);
}
else {
- int i;
printf("\treadonly=");fflush(stdout);
for (i = 0; i < r->method->maxlocals; i++) {
if (r->readonly[i] == true)
}
}
-
+/**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, r->label_index);
-{int i;
+ r->startgp, r->stopgp, r->firstlocal, (void *)r->label_index);
printf ("label_index[0..%d]->", r->method->jcodelength);
-for (i=0; i<r->method->jcodelength; i++) printf ("%d:%d ", i, r->label_index[i]);
+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]);
}
-{
-inlining_methodinfo *im;
-for (im=list_first(r->inlinedmethods);
- im!=NULL;
- im=list_next(r->inlinedmethods,im)) {
- }
-}
+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);
+ }
+ }
+ }
}