1 /* jit/inline.c - code inliner
3 globals moved to structure and passed as parameter
5 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
6 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
7 M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
8 P. Tomsich, J. Wenninger
10 This file is part of CACAO.
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2, or (at
15 your option) any later version.
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 Contact: cacao@complang.tuwien.ac.at
29 Authors: Dieter Thuernbeck
31 $Id: inline.c 1632 2004-11-30 20:42:14Z carolyn $
36 Inlining initializes an inline structure with values of the method called
37 with. Then it recursively to MAXDEPTH analyzes by parsing the bytecode
38 looking for methods that meet the critera to be inlined.
40 Critera for inlining currently is:
41 Method to be inlined must:
42 - be less than MAXCODESIZE
43 - only MAXMETHODS can be inlined in 1 method
45 -in only STATIC, FINAL, PRIVATE methods can be inlined from method's class
46 -ino (include outsiders) all STATIC, FINAL, PRIVATE methods can be inlined
47 -inv include virtual methods which static analysis (currently only RTA)
48 to only have 1 definition used (INVOKEVIRTUAL/INVOKEINTERFACE)
49 Currently dynamic loading is handled by rerunning with info
50 (see parseRT). Guards need to be added.
51 -inp inline parameters (needs work) Parameters are analysed if they are
52 readonly but the information does not seem to be used.
53 -ine JOWENN <- please add
59 #include "mm/memory.h"
60 #include "toolbox/logging.h"
61 #include "vm/global.h"
62 #include "vm/loader.h"
63 #include "vm/tables.h"
64 #include "vm/options.h"
65 #include "vm/jit/jit.h"
66 #include "vm/jit/parse.h"
67 #include "vm/jit/inline/inline.h"
68 #include "vm/jit/inline/sets.h"
70 #undef INVIRTDEBUG /* prints if a method was found to be
71 a unique virt/interface method definition */
74 #define METHINFOj(mm) \
76 printf("<j%i/l%i/s%i/(p)%i>\t", \
77 (mm)->jcodelength,(mm)->maxlocals, \
78 (mm)->maxstack, (mm)->paramcount); \
79 method_display_w_class(mm); }
81 #define METHINFOx(mm) \
83 printf("<c%i/m%i/p%i>\t", \
84 (mm)->class->classUsed,(mm)->methodUsed, (mm)->monoPoly); \
85 method_display_w_class(mm); }
88 method_display_w_class(m);
90 #define IMETHINFO(m) \
91 utf_display(m->class->name); printf("."); fflush(stdout); \
92 method_display(m); fflush(stdout); \
93 printf("\tm->jcodelength=%i; ",m->jcodelength); fflush(stdout); \
94 printf("m->jcode=%p;\n",m->jcode); fflush(stdout); \
95 printf("\tm->maxlocals=%i; ",m->maxlocals); fflush(stdout); \
96 printf("m->maxstack=%i;\n",m->maxstack); fflush(stdout);
98 /* checked functions and macros: LOADCONST code_get OP1 BUILTIN block_insert bound_check ALIGN */
100 /* replace jcodelength loops with correct number after main for loop in parse()! */
102 #define CLASSINFO(cls) \
103 { printf("<c%i>\t",cls->classUsed); \
104 utf_display(cls->name); printf("\n");fflush(stdout);}
106 /*-----------------------------------------------------------*/
107 /* just initialize global structure for non-inlining */
108 /*-----------------------------------------------------------*/
110 void inlining_init0(methodinfo *m, t_inlining_globals *inline_env)
112 /* initialization for normal use in parse */
113 inlining_set_compiler_variables_fun(m, inline_env);
114 inline_env->isinlinedmethod = 0;
115 inline_env->cumjcodelength = m->jcodelength; /* for not inlining */
117 inline_env->cummaxstack = m->maxstack;
118 inline_env->cumextablelength = 0;
119 inline_env->cumlocals = m->maxlocals;
120 inline_env->cummethods = 0; /* co not global or static-used only here? */
121 inline_env->inlining_stack = NULL;
122 inline_env->inlining_rootinfo = NULL;
126 /*-----------------------------------------------------------*/
128 void inlining_setup(methodinfo *m, t_inlining_globals *inline_env)
130 /* t_inlining_globals *inline_env = DNEW(t_inlining_globals); */
131 inlining_init0(m,inline_env);
133 /* define in options.h; Used in main.c, jit.c & inline.c */
135 if ((utf_new_char("main") == m->name) && (useinliningm))
142 printf("\n-------- Inlining init for: "); fflush(stdout);
146 inline_env->cumjcodelength = 0;
147 inline_env->inlining_stack = NEW(list);
148 list_init(inline_env->inlining_stack,
149 OFFSET(t_inlining_stacknode, linkage));
150 /*------ analyze ------*/
151 inline_env->inlining_rootinfo
152 = inlining_analyse_method(m, 0, 0, 0, 0, inline_env);
154 printf ("\n------------------------------ ");fflush(stdout);
155 printf ("\nComplete Result of inlining analysis of:");
158 print_t_inlining_globals(inline_env); /* init ok */
160 /*---------------------*/
162 if (inline_env->cummethods == 0) {
163 inline_env = DNEW(t_inlining_globals);
164 inlining_init0(m,inline_env);
170 printf("(l,s) (%i,%i) was (%i,%i)\n",
171 m->maxlocals, inline_env->cumlocals,
172 m->maxstack, inline_env->cummaxstack); fflush(stdout);
175 /* OK since other changes were also made, but in parse same stmt still */
176 m->maxlocals = inline_env->cumlocals; orig not used
177 m->maxstack = inline_env->cummaxstack; orig global maxstack var!!
183 void inlining_cleanup(t_inlining_globals *inline_env)
185 FREE(inline_env->inlining_stack, t_inlining_stacknode);
189 /*--2 push the compile variables to save the method's environment --*/
191 void inlining_push_compiler_variablesT(int opcode, inlining_methodinfo *inlinfo, t_inlining_globals *inline_env)
193 t_inlining_stacknode *new = NEW(t_inlining_stacknode);
195 /**new->opcode = opcode; **/
196 new->method = inline_env->method;
197 new->inlinfo = inlinfo;
198 list_addfirst(inline_env->inlining_stack, new);
199 inline_env->isinlinedmethod++;
201 /*-- push the compile variables to save the method's environment --*/
203 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)
205 t_inlining_stacknode *new = NEW(t_inlining_stacknode);
210 new->opcode = opcode;
211 new->method = inline_env->method;
212 new->lineindex=lineindex;
213 new->currentline=currentline;
214 new->linepcchange=linepcchange;
215 new->inlinfo = inlinfo;
216 list_addfirst(inline_env->inlining_stack, new);
217 inline_env->isinlinedmethod++;
221 void inlining_pop_compiler_variables(
222 int *i, int *p, int *nextp,
223 int *opcode, u2 *lineindex,
224 u2 *currentline,u2 *linepcchange,
225 inlining_methodinfo **inlinfo,
226 t_inlining_globals *inline_env)
228 t_inlining_stacknode *tmp
229 = (t_inlining_stacknode *) list_first(inline_env->inlining_stack);
231 if (!inline_env->isinlinedmethod) panic("Attempting to pop from inlining stack in toplevel method!\n");
236 *opcode = tmp->opcode;
238 *lineindex=tmp->lineindex;
239 *currentline=tmp->currentline;
240 *currentline=tmp->linepcchange;
242 *inlinfo = tmp->inlinfo;
244 inline_env->method = tmp->method; /*co*/
245 inline_env->class = inline_env->method->class; /*co*/
246 inline_env->jcodelength = inline_env->method->jcodelength; /*co*/
247 inline_env->jcode = inline_env->method->jcode; /*co*/
249 list_remove(inline_env->inlining_stack, tmp);
250 FREE(tmp, t_inlining_stacknode);
251 inline_env->isinlinedmethod--;
255 void inlining_set_compiler_variables_fun(methodinfo *m,
256 t_inlining_globals *inline_env)
258 inline_env->method = m;
259 inline_env->class = m->class;
260 inline_env->jcode = m->jcode;
261 inline_env->jcodelength = m->jcodelength;
264 /* is_unique_method2 - determines if m is a unique method by looking
265 in subclasses of class that define method m
266 It counts as it goes. It also saves the method name if found.
268 returns count of # methods used up to 2
269 (since if 2 used then not unique.)
270 sets mout to method found
271 (unique in class' heirarchy)
272 It looks for subclasses with method def'd.
274 * class - where looking for method
275 * m - original method ptr
276 * mout - unique method (output)
277 Output: "cnt" of methods found up to max of 2 (then not unique)
280 int is_unique_method2(classinfo *class, methodinfo *m, methodinfo **mout)
283 utf* desc = m->descriptor;
285 int cnt = 0; /* number of times method found in USED classes in hierarchy*/
288 if ((m->class == class) && (class->classUsed == USED)) {
289 /* found method in current class, which is used */
296 if ( ((m->flags & ACC_FINAL)
297 || (class->sub == NULL))
298 && (class->classUsed == USED)) {
299 /* if final search no further */
307 /* search for the method in its subclasses */
308 for (subs1 = class->sub;subs1 != NULL;subs1 = subs1->nextsub) {
310 classinfo *subs = subs1;
311 sm = class_resolveclassmethod(subs,name,desc,class,false);
313 if ((subs->classUsed == USED) &&
318 cnt = cnt + is_unique_method2(subs, sm, mout);
319 /* Not unique if more than 1 def of method in class heir */
328 /*-----------------------------------------------------------*/
330 bool is_unique_interface_method (methodinfo *mi, methodinfo **mout) {
332 utf* name = mi->name;
333 utf* desc = mi->descriptor;
336 classSetNode *classImplNode;
339 for (classImplNode = mi->class->impldBy;
340 classImplNode != NULL;
341 classImplNode = classImplNode->nextClass) {
343 classinfo * classImplements = classImplNode->classType;
346 submeth = class_findmethod(classImplements,name, desc);
347 if (submeth != NULL) {
348 icnt =+ is_unique_method2(
353 if (icnt > 1) return false;
355 if (icnt == 1) return true;
359 /*-----------------------------------------------------------*/
361 inlining_methodinfo *inlining_analyse_method(methodinfo *m,
363 int firstlocal, int maxstackdepth,
364 t_inlining_globals *inline_env)
366 inlining_methodinfo *newnode = DNEW(inlining_methodinfo);
367 /*u1 *jcode = m->jcode;*/
368 int jcodelength = m->jcodelength;
373 bool iswide = false, oldiswide;
374 bool *readonly = NULL;
375 int *label_index = NULL;
376 bool isnotrootlevel = (level > 0);
377 bool isnotleaflevel = (level < INLINING_MAXDEPTH);
379 printf ("\n------------------------------ ");fflush(stdout);
380 printf ("\nStart of inlining analysis of: ");fflush(stdout);
382 print_t_inlining_globals(inline_env); /* init ok */
385 /* if (level == 0) gp = 0; */
387 if (isnotrootlevel) {
388 newnode->readonly = readonly = DMNEW(bool, m->maxlocals); /* FIXME only paramcount entrys necessary */
389 for (i = 0; i < m->maxlocals; readonly[i++] = true);
390 isnotrootlevel = true;
396 label_index = DMNEW(int, jcodelength+200);
398 newnode->inlinedmethods = DNEW(list);
399 list_init(newnode->inlinedmethods, OFFSET(inlining_methodinfo, linkage));
402 newnode->level = level;
403 newnode->startgp = gp;
404 newnode->readonly = readonly;
405 newnode->label_index = label_index;
406 newnode->firstlocal = firstlocal;
407 inline_env->cumjcodelength += jcodelength + m->paramcount + 1 + 5;
409 if ((firstlocal + m->maxlocals) > inline_env->cumlocals) {
410 inline_env->cumlocals = firstlocal + m->maxlocals;
413 if ((maxstackdepth + m->maxstack) > inline_env->cummaxstack) {
414 inline_env->cummaxstack = maxstackdepth + m->maxstack;
417 inline_env->cumextablelength += m->exceptiontablelength;
420 for (p = 0; p < jcodelength; gp += (nextp - p), p = nextp) {
421 opcode = code_get_u1 (p,m);
422 nextp = p + jcommandsize[opcode];
425 /* figure out nextp */
459 case JAVA_LOOKUPSWITCH:
460 nextp = ALIGN((p + 1), 4) + 4;
461 nextp += code_get_u4(nextp,m) * 8 + 4;
464 case JAVA_TABLESWITCH:
465 nextp = ALIGN((p + 1), 4) + 4;
466 nextp += (code_get_u4(nextp+4,m) - code_get_u4(nextp,m) + 1) * 4 + 4 +4;
470 /* detect readonly variables in inlined methods */
472 if (isnotrootlevel) {
473 bool iswide = oldiswide;
482 i = code_get_u1(p + 1,m);
485 i = code_get_u2(p + 1,m);
520 i = code_get_u1(p + 1,m);
523 i = code_get_u2(p + 1,m);
530 /* for (i=lastlabel; i<=p; i++) label_index[i] = gp;
531 printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
533 for (i = p; i < nextp; i++) label_index[i] = gp;
535 if (isnotleaflevel) {
539 case JAVA_INVOKEINTERFACE:
540 case JAVA_INVOKEVIRTUAL:
543 case JAVA_INVOKESPECIAL:
544 case JAVA_INVOKESTATIC:
545 i = code_get_u2(p + 1,m);
547 constant_FMIref *imr;
551 bool uniqueVirt= false;
554 if (opcode ==JAVA_INVOKEINTERFACE) {
555 imr = class_getconstant(m->class, i, CONSTANT_InterfaceMethodref);
556 LAZYLOADING(imr->class)
557 imi = class_resolveinterfacemethod(
563 if (!imi) /* extra for debug */
564 panic("ExceptionI thrown while parsing bytecode"); /* XXX should be passed on */
567 imr = class_getconstant(m->class, i, CONSTANT_Methodref);
568 LAZYLOADING(imr->class)
569 imi = class_resolveclassmethod(
575 if (!imi) /* extra for debug */
576 panic("Exception0 thrown while parsing bytecode"); /* XXX should be passed on */
579 if (!imi) /* normal-but never get here now */
580 panic("Exception thrown while parsing bytecode"); /* XXX should be passed on */
582 /** Inlining has problem currently with typecheck & inlining **/
583 /** Due problem with typecheck & inlining, class checks fail for <init>s **/
584 if (utf_new_char("<init>") == imi->name) break;
586 if (opcode == JAVA_INVOKEVIRTUAL) {
588 /* unique virt meth? then */
589 /* allow it to be inlined*/
590 if (is_unique_method2(
599 printf("WAS unique virtual(-iv)\n");fflush(stdout);
602 } /* end is unique */
603 } /* end INVOKEVIRTUAL */
604 if (opcode == JAVA_INVOKEINTERFACE){
609 if (is_unique_interface_method (
617 printf("WAS unique interface(-iv)\n");fflush(stdout);
622 } /* end INVOKEINTERFACE */
624 if ((inline_env->cummethods < INLINING_MAXMETHODS) &&
625 (!(imi->flags & ACC_NATIVE)) &&
626 (inlineoutsiders || (m->class == imr->class)) &&
627 (imi->jcodelength < INLINING_MAXCODESIZE) &&
628 (imi->jcodelength > 0) &&
629 (((!inlinevirtuals) ||
631 ((opcode != JAVA_INVOKEVIRTUAL) ||
632 (opcode != JAVA_INVOKEINTERFACE)) ) &&
633 (inlineexceptions || (imi->exceptiontablelength == 0))) { /* FIXME: eliminate empty methods? */
634 inlining_methodinfo *tmp;
635 descriptor2types(imi);
637 inline_env->cummethods++;
640 char logtext[MAXLOGTEXT];
641 sprintf(logtext, "Going to inline: ");
642 utf_sprint(logtext +strlen(logtext), imi->class->name);
643 strcpy(logtext + strlen(logtext), ".");
644 utf_sprint(logtext + strlen(logtext), imi->name);
645 utf_sprint(logtext + strlen(logtext), imi->descriptor);
648 if ( (!(opcode == JAVA_INVOKEVIRTUAL)) &&
649 (! ( (imi->flags & ACC_STATIC )
650 || (imi->flags & ACC_PRIVATE)
651 || (imi->flags & ACC_FINAL ))) )
653 printf("DEBUG WARNING:PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n"); fflush(stdout);
655 log_text("PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n See method info after DEBUG WARNING\n");
660 tmp =inlining_analyse_method(imi, level + 1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack, inline_env);
661 list_addlast(newnode->inlinedmethods, tmp);
663 printf("New node Right after an inline by:");fflush(stdout);
665 print_inlining_methodinfo(newnode);
666 printf("end new node\n"); fflush(stdout);
677 newnode->stopgp = gp;
678 label_index[jcodelength]=gp;
682 /* --------------------------------------------------------------------*/
683 /* print_ functions: check inline structures contain what is expected */
684 /* --------------------------------------------------------------------*/
685 void print_t_inlining_globals (t_inlining_globals *g)
687 printf("\n------------\nt_inlining_globals struct for: \n\t");fflush(stdout);
688 METHINFOj(g->method);
689 printf("\tclass=");fflush(stdout);
690 utf_display(g->class->name);printf("\n");fflush(stdout);
692 printf("\tjcodelength=%i; jcode=%p;\n",g->jcodelength, g->jcode);
694 if (g->isinlinedmethod==true) {
695 printf("\tisinlinedmethod=true ");fflush(stdout);
698 printf("\tisinlinedmethod=false");fflush(stdout);
701 printf("\tcumjcodelength=%i ,cummaxstack=%i ,cumextablelength=%i ",
702 g->cumjcodelength, g->cummaxstack, g->cumextablelength);fflush(stdout);
703 printf("\tcumlocals=%i ,cummethods=%i \n",
704 g->cumlocals, g->cummethods);fflush(stdout);
706 printf("s>s>s> ");fflush(stdout);
707 print_inlining_stack (g->inlining_stack);
708 printf("i>i>i> "); fflush(stdout);
709 print_inlining_methodinfo(g->inlining_rootinfo);
710 printf("-------------------\n");fflush(stdout);
713 /* --------------------------------------------------------------------*/
714 void print_inlining_stack ( list *s)
716 t_inlining_stacknode *is;
719 printf("\n\tinlining_stack: NULL\n");
723 /* print first element to see if get into stack */
724 printf("\n\tinlining_stack: NOT NULL\n");
728 printf("\n\tinlining_stack = init'd but EMPTY\n");
733 printf("\n\tinlining_stack: NOT NULL\n");
735 for (is=list_first(s);
737 is=list_next(s,is)) {
738 printf("\n\ti>--->inlining_stack entry: \n"); fflush(stdout);
739 METHINFOx(is->method);
740 printf("i=%i, p=%i, nextp=%i, opcode=%i;\n",
741 is->i,is->p,is->nextp,is->opcode);fflush(stdout);
742 print_inlining_methodinfo(is->inlinfo);
746 /* --------------------------------------------------------------------*/
747 void print_inlining_methodinfo( inlining_methodinfo *r) {
750 inlining_methodinfo *im;
751 inlining_methodinfo *im2;
752 bool labellong = false;
755 printf("\n\tinlining_methodinfo: NULL\n");
758 printf("\n\tinlining_methodinfo for:"); fflush(stdout);
760 if (r->method != NULL) {
761 utf_display(r->method->class->name); printf("."); fflush(stdout); \
762 method_display(r->method); fflush(stdout); \
765 printf(" NULL!!!!!\n");fflush(stdout);
768 if (r->readonly==NULL) {
769 printf("\treadonly==NULL ");fflush(stdout);
772 printf("\treadonly=");fflush(stdout);
773 for (i = 0; i < r->method->maxlocals; i++) {
774 if (r->readonly[i] == true)
783 printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n",
784 r->startgp, r->stopgp, r->firstlocal, r->label_index);
785 printf ("label_index[0..%d]->", r->method->jcodelength);
787 for (i=0; i<r->method->jcodelength; i++) printf ("%d:%d ", i, r->label_index[i]); }
789 printf ("%d:%d ", 0, r->label_index[i]);
791 (r->method->jcodelength-1), r->label_index[r->method->jcodelength-1]);
794 printf("\n:::::inlines::::::::::::::::::::\n");
795 if (list_first(r->inlinedmethods) == NULL) {
796 printf("Nothing\n");fflush(stdout);
799 for (im=list_first(r->inlinedmethods),cnt=0;
801 im=list_next(r->inlinedmethods,im),cnt++) {
802 printf("*"); fflush(stdout);
804 printf("[1L%i] ",im->firstlocal); fflush(stdout);
805 METHINFOj(im->method)
806 printf("::::: which inlines::"); fflush(stdout);
807 if (list_first(im->inlinedmethods) == NULL) {
808 printf("Nothing\n");fflush(stdout);
811 printf("##"); fflush(stdout);
812 for (im2=list_first(im->inlinedmethods),cnt2=0;
814 im2=list_next(im2->inlinedmethods,im2),cnt2++)
816 printf("\t%i::",cnt2); fflush(stdout);
817 printf("[1L%i] ",im2->firstlocal);
819 METHINFOj(im2->method)
821 printf("\n"); fflush(stdout);
829 * These are local overrides for various environment variables in Emacs.
830 * Please do not remove this and leave it at the end of the file, where
831 * Emacs will automagically detect them.
832 * ---------------------------------------------------------------------
835 * indent-tabs-mode: t