1 /* jit/inline.c - code inliner
3 globals moved to structure and passed as parameter
5 Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
6 R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
7 C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
8 Institut f. Computersprachen - TU Wien
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 1750 2004-12-10 23:21:03Z 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 note: PRIVATE is always only in the same class
48 -inv include virtual methods which static analysis (currently only RTA)
49 to only have 1 definition used (INVOKEVIRTUAL/INVOKEINTERFACE)
50 Currently dynamic loading is handled by rerunning with info
51 (see parseRT). Guards need to be added.
52 -inp inline parameters - Parameters are analysed if they are
53 readonly, which is used during parsing to generate ICMD_CLEAR_ARGREN
54 and ICMD_CLEAR_ARGREN is in turn used during stack analysis to
55 replace the ISTORE with a NOP so the same local variable is used.
56 Parameters are pushed on the stack, same as normal method
57 invocation when popped the local variable of calling program is used.
58 -ine JOWENN <- please add
64 #include "mm/memory.h"
65 #include "toolbox/logging.h"
66 #include "vm/global.h"
67 #include "vm/loader.h"
68 #include "vm/tables.h"
69 #include "vm/options.h"
70 #include "vm/jit/jit.h"
71 #include "vm/jit/parse.h"
72 #include "vm/jit/inline/inline.h"
73 #include "vm/jit/inline/sets.h"
75 #undef INVIRTDEBUG /* prints if a method was found to be
76 a unique virt/interface method definition */
79 #define METHINFOj(mm) \
81 printf("<j%i/l%i/s%i/(p)%i>\t", \
82 (mm)->jcodelength,(mm)->maxlocals, \
83 (mm)->maxstack, (mm)->paramcount); \
84 method_display_w_class(mm); }
86 #define METHINFOx(mm) \
88 printf("<c%i/m%i/p%i>\t", \
89 (mm)->class->classUsed,(mm)->methodUsed, (mm)->monoPoly); \
90 method_display_w_class(mm); }
93 method_display_w_class(m);
95 #define IMETHINFO(m) \
96 utf_display(m->class->name); printf("."); fflush(stdout); \
97 method_display(m); fflush(stdout); \
98 printf("\tm->jcodelength=%i; ",m->jcodelength); fflush(stdout); \
99 printf("m->jcode=%p;\n",m->jcode); fflush(stdout); \
100 printf("\tm->maxlocals=%i; ",m->maxlocals); fflush(stdout); \
101 printf("m->maxstack=%i;\n",m->maxstack); fflush(stdout);
103 /* checked functions and macros: LOADCONST code_get OP1 BUILTIN block_insert bound_check ALIGN */
105 /* replace jcodelength loops with correct number after main for loop in parse()! */
107 #define CLASSINFO(cls) \
108 { printf("<c%i>\t",cls->classUsed); \
109 utf_display(cls->name); printf("\n");fflush(stdout);}
111 /*-----------------------------------------------------------*/
112 /* just initialize global structure for non-inlining */
113 /*-----------------------------------------------------------*/
115 void inlining_init0(methodinfo *m, t_inlining_globals *inline_env)
117 /* initialization for normal use in parse */
118 inlining_set_compiler_variables_fun(m, inline_env);
119 inline_env->isinlinedmethod = 0;
120 inline_env->cumjcodelength = m->jcodelength; /* for not inlining */
122 inline_env->cummaxstack = m->maxstack;
123 inline_env->cumextablelength = 0;
124 inline_env->cumlocals = m->maxlocals;
125 inline_env->cummethods = 0; /* co not global or static-used only here? */
126 inline_env->inlining_stack = NULL;
127 inline_env->inlining_rootinfo = NULL;
131 /*-----------------------------------------------------------*/
133 void inlining_setup(methodinfo *m, t_inlining_globals *inline_env)
135 /* t_inlining_globals *inline_env = DNEW(t_inlining_globals); */
136 inlining_init0(m,inline_env);
138 /* define in options.h; Used in main.c, jit.c & inline.c */
140 if ((utf_new_char("main") == m->name) && (useinliningm)) {
148 printf("\n-------- Inlining init for: "); fflush(stdout);
152 inline_env->cumjcodelength = 0;
153 inline_env->inlining_stack = NEW(list);
154 list_init(inline_env->inlining_stack,
155 OFFSET(t_inlining_stacknode, linkage));
156 /*------ analyze ------*/
157 inline_env->inlining_rootinfo
158 = inlining_analyse_method(m, 0, 0, 0, 0, inline_env);
160 printf ("\n------------------------------ ");fflush(stdout);
161 printf ("\nComplete Result of inlining analysis of:");
164 print_t_inlining_globals(inline_env); /* init ok */
166 /*---------------------*/
168 if (inline_env->cummethods == 0) {
169 inline_env = DNEW(t_inlining_globals);
170 inlining_init0(m,inline_env);
176 printf("(l,s) (%i,%i) was (%i,%i)\n",
177 m->maxlocals, inline_env->cumlocals,
178 m->maxstack, inline_env->cummaxstack); fflush(stdout);
181 /* OK since other changes were also made, but in parse same stmt still */
182 m->maxlocals = inline_env->cumlocals; orig not used
183 m->maxstack = inline_env->cummaxstack; orig global maxstack var!!
189 void inlining_cleanup(t_inlining_globals *inline_env)
191 FREE(inline_env->inlining_stack, t_inlining_stacknode);
195 /*--2 push the compile variables to save the method's environment --*/
197 void inlining_push_compiler_variablesT(int opcode, inlining_methodinfo *inlinfo, t_inlining_globals *inline_env)
199 t_inlining_stacknode *new = NEW(t_inlining_stacknode);
201 /**new->opcode = opcode; **/
202 new->method = inline_env->method;
203 new->inlinfo = inlinfo;
204 list_addfirst(inline_env->inlining_stack, new);
205 inline_env->isinlinedmethod++;
207 /*-- push the compile variables to save the method's environment --*/
209 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)
211 t_inlining_stacknode *new = NEW(t_inlining_stacknode);
216 new->opcode = opcode;
217 new->method = inline_env->method;
218 new->lineindex=lineindex;
219 new->currentline=currentline;
220 new->linepcchange=linepcchange;
221 new->inlinfo = inlinfo;
222 list_addfirst(inline_env->inlining_stack, new);
223 inline_env->isinlinedmethod++;
227 void inlining_pop_compiler_variables(
228 int *i, int *p, int *nextp,
229 int *opcode, u2 *lineindex,
230 u2 *currentline,u2 *linepcchange,
231 inlining_methodinfo **inlinfo,
232 t_inlining_globals *inline_env)
234 t_inlining_stacknode *tmp
235 = (t_inlining_stacknode *) list_first(inline_env->inlining_stack);
237 if (!inline_env->isinlinedmethod) panic("Attempting to pop from inlining stack in toplevel method!\n");
242 *opcode = tmp->opcode;
244 *lineindex=tmp->lineindex;
245 *currentline=tmp->currentline;
246 *currentline=tmp->linepcchange;
248 *inlinfo = tmp->inlinfo;
250 inline_env->method = tmp->method; /*co*/
251 inline_env->class = inline_env->method->class; /*co*/
252 inline_env->jcodelength = inline_env->method->jcodelength; /*co*/
253 inline_env->jcode = inline_env->method->jcode; /*co*/
255 list_remove(inline_env->inlining_stack, tmp);
256 FREE(tmp, t_inlining_stacknode);
257 inline_env->isinlinedmethod--;
261 void inlining_set_compiler_variables_fun(methodinfo *m,
262 t_inlining_globals *inline_env)
264 inline_env->method = m;
265 inline_env->class = m->class;
266 inline_env->jcode = m->jcode;
267 inline_env->jcodelength = m->jcodelength;
270 /* is_unique_method2 - determines if m is a unique method by looking
271 in subclasses of class that define method m
272 It counts as it goes. It also saves the method name if found.
274 returns count of # methods used up to 2
275 (since if 2 used then not unique.)
276 sets mout to method found
277 (unique in class' heirarchy)
278 It looks for subclasses with method def'd.
280 * class - where looking for method
281 * m - original method ptr
282 * mout - unique method (output)
283 Output: "cnt" of methods found up to max of 2 (then not unique)
286 int is_unique_method2(classinfo *class, methodinfo *m, methodinfo **mout)
289 utf* desc = m->descriptor;
291 int cnt = 0; /* number of times method found in USED classes in hierarchy*/
294 if ((m->class == class) && (class->classUsed == USED)) {
295 /* found method in current class, which is used */
302 if ( ((m->flags & ACC_FINAL)
303 || (class->sub == NULL))
304 && (class->classUsed == USED)) {
305 /* if final search no further */
313 /* search for the method in its subclasses */
314 for (subs1 = class->sub;subs1 != NULL;subs1 = subs1->nextsub) {
316 classinfo *subs = subs1;
317 sm = class_resolveclassmethod(subs,name,desc,class,false);
319 if ((subs->classUsed == USED) &&
324 cnt = cnt + is_unique_method2(subs, sm, mout);
325 /* Not unique if more than 1 def of method in class heir */
334 /*-----------------------------------------------------------*/
336 bool is_unique_interface_method (methodinfo *mi, methodinfo **mout) {
338 utf* name = mi->name;
339 utf* desc = mi->descriptor;
341 classSetNode *classImplNode;
344 for (classImplNode = mi->class->impldBy;
345 classImplNode != NULL;
346 classImplNode = classImplNode->nextClass) {
348 classinfo * classImplements = classImplNode->classType;
351 submeth = class_findmethod(classImplements,name, desc);
352 if (submeth != NULL) {
353 icnt =+ is_unique_method2(
358 if (icnt > 1) return false;
360 if (icnt == 1) return true;
364 /*-----------------------------------------------------------*/
366 inlining_methodinfo *inlining_analyse_method(methodinfo *m,
368 int firstlocal, int maxstackdepth,
369 t_inlining_globals *inline_env)
371 inlining_methodinfo *newnode = DNEW(inlining_methodinfo);
372 /*u1 *jcode = m->jcode;*/
373 int jcodelength = m->jcodelength;
378 bool iswide = false, oldiswide;
379 bool *readonly = NULL;
380 int *label_index = NULL;
381 bool isnotrootlevel = (level > 0);
382 bool isnotleaflevel = (level < INLINING_MAXDEPTH);
384 printf ("\n------------------------------ ");fflush(stdout);
385 printf ("\nStart of inlining analysis of: ");fflush(stdout);
387 if (isnotrootlevel) printf(" isnotrootlevel=T ");
388 else printf(" isnotrootlevel=F ");
389 print_t_inlining_globals(inline_env); /* init ok */
393 /* if (level == 0) gp = 0; */
395 if (isnotrootlevel) {
396 newnode->readonly = readonly = DMNEW(bool, m->maxlocals); /* FIXME only paramcount entrys necessary - ok FIXED also turned on*/
398 /** for (i = 0; i < m->maxlocals; readonly[i++] = true); **/
399 for (i = 0; i < m->paramcount; readonly[i++] = true);
400 /***isnotrootlevel = true; This had turned -inp off **/
406 label_index = DMNEW(int, jcodelength+200);
408 newnode->inlinedmethods = DNEW(list);
409 list_init(newnode->inlinedmethods, OFFSET(inlining_methodinfo, linkage));
412 newnode->level = level;
413 newnode->startgp = gp;
414 newnode->readonly = readonly;
415 newnode->label_index = label_index;
416 newnode->firstlocal = firstlocal;
417 inline_env->cumjcodelength += jcodelength + m->paramcount + 1 + 5;
419 if ((firstlocal + m->maxlocals) > inline_env->cumlocals) {
420 inline_env->cumlocals = firstlocal + m->maxlocals;
423 if ((maxstackdepth + m->maxstack) > inline_env->cummaxstack) {
424 inline_env->cummaxstack = maxstackdepth + m->maxstack;
427 inline_env->cumextablelength += m->exceptiontablelength;
430 for (p = 0; p < jcodelength; gp += (nextp - p), p = nextp) {
431 opcode = code_get_u1 (p,m);
432 nextp = p + jcommandsize[opcode];
435 /* figure out nextp */
469 case JAVA_LOOKUPSWITCH:
470 nextp = ALIGN((p + 1), 4) + 4;
471 nextp += code_get_u4(nextp,m) * 8 + 4;
474 case JAVA_TABLESWITCH:
475 nextp = ALIGN((p + 1), 4) + 4;
476 nextp += (code_get_u4(nextp+4,m) - code_get_u4(nextp,m) + 1) * 4 + 4 +4;
480 /* detect readonly variables in inlined methods */
482 if (isnotrootlevel) {
483 bool iswide = oldiswide;
492 i = code_get_u1(p + 1,m);
495 i = code_get_u2(p + 1,m);
530 i = code_get_u1(p + 1,m);
533 i = code_get_u2(p + 1,m);
540 /* for (i=lastlabel; i<=p; i++) label_index[i] = gp;
541 printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
543 for (i = p; i < nextp; i++) label_index[i] = gp;
545 if (isnotleaflevel) {
549 case JAVA_INVOKEINTERFACE:
550 case JAVA_INVOKEVIRTUAL:
554 case JAVA_INVOKESPECIAL:
555 case JAVA_INVOKESTATIC:
556 i = code_get_u2(p + 1,m);
558 constant_FMIref *imr;
562 bool uniqueVirt= false;
565 if (opcode ==JAVA_INVOKEINTERFACE) {
566 imr = class_getconstant(m->class, i, CONSTANT_InterfaceMethodref);
567 LAZYLOADING(imr->class)
568 imi = class_resolveinterfacemethod(
574 if (!imi) /* extra for debug */
575 panic("ExceptionI thrown while parsing bytecode"); /* XXX should be passed on */
578 imr = class_getconstant(m->class, i, CONSTANT_Methodref);
579 LAZYLOADING(imr->class)
580 imi = class_resolveclassmethod(
586 if (!imi) /* extra for debug */
587 panic("Exception0 thrown while parsing bytecode"); /* XXX should be passed on */
590 if (!imi) /* normal-but never get here now */
591 panic("Exception thrown while parsing bytecode"); /* XXX should be passed on */
593 /** Inlining has problem currently with typecheck & inlining **/
594 /** Due problem with typecheck & inlining, class checks fail for <init>s **/
595 if (utf_new_char("<init>") == imi->name) break;
597 if (opcode == JAVA_INVOKEVIRTUAL) {
599 /* unique virt meth? then */
600 /* allow it to be inlined*/
601 if (is_unique_method2(
610 printf("WAS unique virtual(-iv)\n");fflush(stdout);
613 } /* end is unique */
614 } /* end INVOKEVIRTUAL */
615 if (opcode == JAVA_INVOKEINTERFACE){
620 if (is_unique_interface_method (
628 printf("WAS unique interface(-iv)\n");fflush(stdout);
633 } /* end INVOKEINTERFACE */
635 if ((inline_env->cummethods < INLINING_MAXMETHODS) &&
636 (!(imi->flags & ACC_NATIVE)) &&
637 (inlineoutsiders || (m->class == imr->class)) &&
638 (imi->jcodelength < INLINING_MAXCODESIZE) &&
639 (imi->jcodelength > 0) &&
640 (((!inlinevirtuals) ||
642 ((opcode != JAVA_INVOKEVIRTUAL) ||
643 (opcode != JAVA_INVOKEINTERFACE)) ) &&
644 (inlineexceptions || (imi->exceptiontablelength == 0))) { /* FIXME: eliminate empty methods? */
645 inlining_methodinfo *tmp;
646 descriptor2types(imi);
648 inline_env->cummethods++;
651 char logtext[MAXLOGTEXT];
652 sprintf(logtext, "Going to inline: ");
653 utf_sprint(logtext +strlen(logtext), imi->class->name);
654 strcpy(logtext + strlen(logtext), ".");
655 utf_sprint(logtext + strlen(logtext), imi->name);
656 utf_sprint(logtext + strlen(logtext), imi->descriptor);
658 if ( (!(opcode == JAVA_INVOKEVIRTUAL)) &&
659 (! ( (imi->flags & ACC_STATIC )
660 || ((imi->flags & ACC_PRIVATE) && (imi->class == inline_env->class))
661 || (imi->flags & ACC_FINAL ))) )
663 printf("DEBUG WARNING:PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n"); fflush(stdout);
665 log_text("PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n See method info after DEBUG WARNING\n");
670 tmp =inlining_analyse_method(imi, level + 1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack, inline_env);
671 list_addlast(newnode->inlinedmethods, tmp);
673 printf("New node Right after an inline by:");fflush(stdout);
675 print_inlining_methodinfo(newnode);
676 printf("end new node\n"); fflush(stdout);
687 newnode->stopgp = gp;
688 label_index[jcodelength]=gp;
692 /* --------------------------------------------------------------------*/
693 /* print_ functions: check inline structures contain what is expected */
694 /* --------------------------------------------------------------------*/
695 void print_t_inlining_globals (t_inlining_globals *g)
697 printf("\n------------\nt_inlining_globals struct for: \n\t");fflush(stdout);
698 METHINFOj(g->method);
699 printf("\tclass=");fflush(stdout);
700 utf_display(g->class->name);printf("\n");fflush(stdout);
702 printf("\tjcodelength=%i; jcode=%p;\n",g->jcodelength, g->jcode);
704 if (g->isinlinedmethod==true) {
705 printf("\tisinlinedmethod=true ");fflush(stdout);
708 printf("\tisinlinedmethod=false");fflush(stdout);
711 printf("\tcumjcodelength=%i ,cummaxstack=%i ,cumextablelength=%i ",
712 g->cumjcodelength, g->cummaxstack, g->cumextablelength);fflush(stdout);
713 printf("\tcumlocals=%i ,cummethods=%i \n",
714 g->cumlocals, g->cummethods);fflush(stdout);
716 printf("s>s>s> ");fflush(stdout);
717 print_inlining_stack (g->inlining_stack);
718 printf("i>i>i> "); fflush(stdout);
719 print_inlining_methodinfo(g->inlining_rootinfo);
720 printf("-------------------\n");fflush(stdout);
723 /* --------------------------------------------------------------------*/
724 void print_inlining_stack ( list *s)
726 t_inlining_stacknode *is;
729 printf("\n\tinlining_stack: NULL\n");
733 /* print first element to see if get into stack */
734 printf("\n\tinlining_stack: NOT NULL\n");
738 printf("\n\tinlining_stack = init'd but EMPTY\n");
743 printf("\n\tinlining_stack: NOT NULL\n");
745 for (is=list_first(s);
747 is=list_next(s,is)) {
748 printf("\n\ti>--->inlining_stack entry: \n"); fflush(stdout);
749 METHINFOx(is->method);
750 printf("i=%i, p=%i, nextp=%i, opcode=%i;\n",
751 is->i,is->p,is->nextp,is->opcode);fflush(stdout);
752 print_inlining_methodinfo(is->inlinfo);
756 /* --------------------------------------------------------------------*/
757 void print_inlining_methodinfo( inlining_methodinfo *r) {
760 inlining_methodinfo *im;
761 inlining_methodinfo *im2;
762 bool labellong = false;
765 printf("\n\tinlining_methodinfo: NULL\n");
768 printf("\n\tinlining_methodinfo for:"); fflush(stdout);
770 if (r->method != NULL) {
771 utf_display(r->method->class->name); printf("."); fflush(stdout); \
772 method_display(r->method); fflush(stdout); \
775 printf(" NULL!!!!!\n");fflush(stdout);
778 if (r->readonly==NULL) {
779 printf("\treadonly==NULL ");fflush(stdout);
782 printf("\treadonly=");fflush(stdout);
783 for (i = 0; i < r->method->maxlocals; i++) {
784 if (r->readonly[i] == true)
792 /**printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n", **/
793 printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n",
794 r->startgp, r->stopgp, r->firstlocal, (void *)r->label_index);
795 printf ("label_index[0..%d]->", r->method->jcodelength);
797 for (i=0; i<r->method->jcodelength; i++) printf ("%d:%d ", i, r->label_index[i]); }
799 printf ("%d:%d ", 0, r->label_index[i]);
801 (r->method->jcodelength-1), r->label_index[r->method->jcodelength-1]);
804 printf("\n:::::inlines::::::::::::::::::::\n");
805 if (list_first(r->inlinedmethods) == NULL) {
806 printf("Nothing\n");fflush(stdout);
809 for (im=list_first(r->inlinedmethods),cnt=0;
811 im=list_next(r->inlinedmethods,im),cnt++) {
812 printf("*"); fflush(stdout);
814 printf("[1L%i] ",im->firstlocal); fflush(stdout);
815 METHINFOj(im->method)
816 printf("::::: which inlines::"); fflush(stdout);
817 if (list_first(im->inlinedmethods) == NULL) {
818 printf("Nothing\n");fflush(stdout);
821 printf("##"); fflush(stdout);
822 for (im2=list_first(im->inlinedmethods),cnt2=0;
824 im2=list_next(im2->inlinedmethods,im2),cnt2++)
826 printf("\t%i::",cnt2); fflush(stdout);
827 printf("[1L%i] ",im2->firstlocal);
829 METHINFOj(im2->method)
831 printf("\n"); fflush(stdout);
839 * These are local overrides for various environment variables in Emacs.
840 * Please do not remove this and leave it at the end of the file, where
841 * Emacs will automagically detect them.
842 * ---------------------------------------------------------------------
845 * indent-tabs-mode: t