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 1557 2004-11-22 12:01:16Z carolyn $
42 #include "jit/inline.h"
44 #include "jit/parse.h"
45 #include "toolbox/logging.h"
46 #include "toolbox/memory.h"
52 #define METHINFOx(mm) \
54 printf("<c%i/m%i/p%i>\t", \
55 (mm)->class->classUsed,(mm)->methodUsed, (mm)->monoPoly); \
56 method_display_w_class(mm); }
59 method_display_w_class(m);
61 #define IMETHINFO(m) \
62 utf_display(m->class->name); printf("."); fflush(stdout); \
63 method_display(m); fflush(stdout); \
64 printf("\tm->jcodelength=%i; ",m->jcodelength); fflush(stdout); \
65 printf("m->jcode=%p;\n",m->jcode); fflush(stdout); \
66 printf("\tm->maxlocals=%i; ",m->maxlocals); fflush(stdout); \
67 printf("m->maxstack=%i;\n",m->maxstack); fflush(stdout);
70 /* checked functions and macros: LOADCONST code_get OP1 BUILTIN block_insert bound_check ALIGN */
72 /* replace jcodelength loops with correct number after main for loop in parse()! */
74 #define CLASSINFO(cls) \
75 { printf("<c%i>\t",cls->classUsed); \
76 utf_display(cls->name); printf("\n");fflush(stdout);}
78 /*-----------------------------------------------------------*/
79 /* just initialize global structure for non-inlining */
80 /*-----------------------------------------------------------*/
82 void inlining_init0(methodinfo *m, t_inlining_globals *inline_env)
84 /* initialization for normal use in parse */
85 inlining_set_compiler_variables_fun(m, inline_env);
86 inline_env->isinlinedmethod = 0;
87 inline_env->cumjcodelength = m->jcodelength; /* for not inlining */
89 inline_env->cummaxstack = m->maxstack;
90 inline_env->cumextablelength = 0;
91 inline_env->cumlocals = m->maxlocals;
92 inline_env->cummethods = 0; /* co not global or static-used only here? */
93 inline_env->inlining_stack = NULL;
94 inline_env->inlining_rootinfo = NULL;
98 /*-----------------------------------------------------------*/
100 void inlining_setup(methodinfo *m, t_inlining_globals *inline_env)
102 /* t_inlining_globals *inline_env = DNEW(t_inlining_globals); */
103 inlining_init0(m,inline_env);
105 /* define in options.h; Used in main.c, jit.c & inline.c */
107 if ((utf_new_char("main") == m->name) && (useinliningm))
114 printf("\n-------- Inlining init for: "); fflush(stdout);
117 inline_env->cumjcodelength = 0;
118 inline_env->inlining_stack = NEW(list);
119 list_init(inline_env->inlining_stack,
120 OFFSET(t_inlining_stacknode, linkage));
121 /*------ analyze ------*/
122 if (DEBUGi==true) {print_t_inlining_globals(inline_env);}
123 inline_env->inlining_rootinfo
124 = inlining_analyse_method(m, 0, 0, 0, 0, inline_env);
125 if (DEBUGi==true) {print_t_inlining_globals(inline_env);}
126 /*---------------------*/
128 if (inline_env->cummethods == 0) {
129 inline_env = DNEW(t_inlining_globals);
130 inlining_init0(m,inline_env);
135 printf("(l,s) (%i,%i) was (%i,%i)\n",
136 m->maxlocals, inline_env->cumlocals,
137 m->maxstack, inline_env->cummaxstack); fflush(stdout);
141 m->maxlocals = inline_env->cumlocals; orig not used
142 m->maxstack = inline_env->cummaxstack; orig global maxstack var!!
148 void inlining_cleanup(t_inlining_globals *inline_env)
150 FREE(inline_env->inlining_stack, t_inlining_stacknode);
154 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)
156 t_inlining_stacknode *new = NEW(t_inlining_stacknode);
161 new->opcode = opcode;
162 new->method = inline_env->method;
163 new->lineindex=lineindex;
164 new->currentline=currentline;
165 new->linepcchange=linepcchange;
166 new->inlinfo = inlinfo;
167 list_addfirst(inline_env->inlining_stack, new);
168 inline_env->isinlinedmethod++;
172 void inlining_pop_compiler_variables(
173 int *i, int *p, int *nextp,
174 int *opcode, u2 *lineindex,
175 u2 *currentline,u2 *linepcchange,
176 inlining_methodinfo **inlinfo,
177 t_inlining_globals *inline_env)
179 t_inlining_stacknode *tmp
180 = (t_inlining_stacknode *) list_first(inline_env->inlining_stack);
182 if (!inline_env->isinlinedmethod) panic("Attempting to pop from inlining stack in toplevel method!\n");
187 *opcode = tmp->opcode;
189 *lineindex=tmp->lineindex;
190 *currentline=tmp->currentline;
191 *currentline=tmp->linepcchange;
193 *inlinfo = tmp->inlinfo;
195 inline_env->method = tmp->method; /*co*/
196 inline_env->class = inline_env->method->class; /*co*/
197 inline_env->jcodelength = inline_env->method->jcodelength; /*co*/
198 inline_env->jcode = inline_env->method->jcode; /*co*/
200 list_remove(inline_env->inlining_stack, tmp);
201 FREE(tmp, t_inlining_stacknode);
202 inline_env->isinlinedmethod--;
206 void inlining_set_compiler_variables_fun(methodinfo *m,
207 t_inlining_globals *inline_env)
209 inline_env->method = m;
210 inline_env->class = m->class;
211 inline_env->jcode = m->jcode;
212 inline_env->jcodelength = m->jcodelength;
215 /* is_unique_method2 - determines if m is a unique method by looking
216 in subclasses of class that define method m
217 It counts as it goes. It also saves the method name if found.
219 returns count of # methods used up to 2
220 (since if 2 used then not unique.)
221 sets mout to method found
222 (unique in class' heirarchy)
223 It looks for subclasses with method def'd.
225 * class - where looking for method
226 * m - original method ptr
227 * mout - unique method (output)
228 Output: "cnt" of methods found up to max of 2 (then not unique)
231 int is_unique_method2(classinfo *class, methodinfo *m, methodinfo **mout)
234 utf* desc = m->descriptor;
236 int cnt = 0; /* number of times method found in USED classes in hierarchy*/
239 if ((m->class == class) && (class->classUsed == USED)) {
240 /* found method in current class, which is used */
247 if ( ((m->flags & ACC_FINAL)
248 || (class->sub == NULL))
249 && (class->classUsed == USED)) {
250 /* if final search no further */
258 /* search for the method in its subclasses */
259 for (subs1 = class->sub;subs1 != NULL;subs1 = subs1->nextsub) {
261 classinfo *subs = subs1;
262 sm = class_resolveclassmethod(subs,name,desc,class,false);
264 if ((subs->classUsed == USED) &&
269 cnt = cnt + is_unique_method2(subs, sm, mout);
270 /* Not unique if more than 1 def of method in class heir */
279 /*-----------------------------------------------------------*/
281 bool is_unique_interface_method (methodinfo *mi, methodinfo **mout) {
283 utf* name = mi->name;
284 utf* desc = mi->descriptor;
287 classSetNode *classImplNode;
290 for (classImplNode = mi->class->impldBy;
291 classImplNode != NULL;
292 classImplNode = classImplNode->nextClass) {
294 classinfo * classImplements = classImplNode->classType;
297 submeth = class_findmethod(classImplements,name, desc);
298 if (submeth != NULL) {
299 icnt =+ is_unique_method2(
304 if (icnt > 1) return false;
306 if (icnt == 1) return true;
310 /*-----------------------------------------------------------*/
312 inlining_methodinfo *inlining_analyse_method(methodinfo *m,
314 int firstlocal, int maxstackdepth,
315 t_inlining_globals *inline_env)
317 inlining_methodinfo *newnode = DNEW(inlining_methodinfo);
318 /*u1 *jcode = m->jcode;*/
319 int jcodelength = m->jcodelength;
324 bool iswide = false, oldiswide;
325 bool *readonly = NULL;
326 int *label_index = NULL;
327 bool isnotrootlevel = (level > 0);
328 bool isnotleaflevel = (level < INLINING_MAXDEPTH);
330 /* if (level == 0) gp = 0; */
332 sprintf (logtext, "Performing inlining analysis of: ");
333 utf_sprint (logtext+strlen(logtext), m->class->name);
334 strcpy (logtext+strlen(logtext), ".");
335 utf_sprint (logtext+strlen(logtext), m->name);
336 utf_sprint (logtext+strlen(logtext), m->descriptor);
339 if (isnotrootlevel) {
340 newnode->readonly = readonly = DMNEW(bool, m->maxlocals); /* FIXME only paramcount entrys necessary */
341 for (i = 0; i < m->maxlocals; readonly[i++] = true);
342 isnotrootlevel = true;
348 label_index = DMNEW(int, jcodelength+200);
350 newnode->inlinedmethods = DNEW(list);
351 list_init(newnode->inlinedmethods, OFFSET(inlining_methodinfo, linkage));
354 newnode->startgp = gp;
355 newnode->readonly = readonly;
356 newnode->label_index = label_index;
357 newnode->firstlocal = firstlocal;
358 inline_env->cumjcodelength += jcodelength + m->paramcount + 1 + 5;
360 if ((firstlocal + m->maxlocals) > inline_env->cumlocals) {
361 inline_env->cumlocals = firstlocal + m->maxlocals;
364 if ((maxstackdepth + m->maxstack) > inline_env->cummaxstack) {
365 inline_env->cummaxstack = maxstackdepth + m->maxstack;
368 inline_env->cumextablelength += m->exceptiontablelength;
371 for (p = 0; p < jcodelength; gp += (nextp - p), p = nextp) {
372 opcode = code_get_u1 (p,m);
373 nextp = p + jcommandsize[opcode];
376 /* figure out nextp */
410 case JAVA_LOOKUPSWITCH:
411 nextp = ALIGN((p + 1), 4) + 4;
412 nextp += code_get_u4(nextp,m) * 8 + 4;
415 case JAVA_TABLESWITCH:
416 nextp = ALIGN((p + 1), 4) + 4;
417 nextp += (code_get_u4(nextp+4,m) - code_get_u4(nextp,m) + 1) * 4 + 4 +4;
421 /* detect readonly variables in inlined methods */
423 if (isnotrootlevel) {
424 bool iswide = oldiswide;
433 i = code_get_u1(p + 1,m);
436 i = code_get_u2(p + 1,m);
471 i = code_get_u1(p + 1,m);
474 i = code_get_u2(p + 1,m);
481 /* for (i=lastlabel; i<=p; i++) label_index[i] = gp;
482 printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
484 for (i = p; i < nextp; i++) label_index[i] = gp;
486 if (isnotleaflevel) {
490 case JAVA_INVOKEINTERFACE:
491 case JAVA_INVOKEVIRTUAL:
494 case JAVA_INVOKESPECIAL:
495 case JAVA_INVOKESTATIC:
496 i = code_get_u2(p + 1,m);
498 constant_FMIref *imr;
502 bool uniqueVirt= false;
505 if (opcode ==JAVA_INVOKEINTERFACE) {
506 imr = class_getconstant(m->class, i, CONSTANT_InterfaceMethodref);
507 LAZYLOADING(imr->class)
508 imi = class_resolveinterfacemethod(
514 if (!imi) /* extra for debug */
515 panic("ExceptionI thrown while parsing bytecode"); /* XXX should be passed on */
518 imr = class_getconstant(m->class, i, CONSTANT_Methodref);
519 LAZYLOADING(imr->class)
520 imi = class_resolveclassmethod(
526 if (!imi) /* extra for debug */
527 panic("Exception0 thrown while parsing bytecode"); /* XXX should be passed on */
530 if (!imi) /* normal-but never get here now */
531 panic("Exception thrown while parsing bytecode"); /* XXX should be passed on */
533 /** Inlining inits has problem currently **/
534 if (utf_new_char("<init>") == imi->name) break;
536 if (opcode == JAVA_INVOKEVIRTUAL) {
538 /* unique virt meth? then */
539 /* allow it to be inlined*/
540 if (is_unique_method2(
549 printf("WAS unique virtual(-iv)\n");fflush(stdout);
552 } /* end is unique */
553 } /* end INVOKEVIRTUAL */
554 if (opcode == JAVA_INVOKEINTERFACE){
559 if (is_unique_interface_method (
567 printf("WAS unique interface(-iv)\n");fflush(stdout);
572 } /* end INVOKEINTERFACE */
574 if ((inline_env->cummethods < INLINING_MAXMETHODS) &&
575 (!(imi->flags & ACC_NATIVE)) &&
576 (inlineoutsiders || (m->class == imr->class)) &&
577 (imi->jcodelength < INLINING_MAXCODESIZE) &&
578 (imi->jcodelength > 0) &&
579 (((!inlinevirtuals) ||
581 ((opcode != JAVA_INVOKEVIRTUAL) ||
582 (opcode != JAVA_INVOKEINTERFACE)) ) &&
583 (inlineexceptions || (imi->exceptiontablelength == 0))) { /* FIXME: eliminate empty methods? */
584 inlining_methodinfo *tmp;
585 descriptor2types(imi);
587 inline_env->cummethods++;
590 char logtext[MAXLOGTEXT];
591 sprintf(logtext, "Going to inline: ");
592 utf_sprint(logtext +strlen(logtext), imi->class->name);
593 strcpy(logtext + strlen(logtext), ".");
594 utf_sprint(logtext + strlen(logtext), imi->name);
595 utf_sprint(logtext + strlen(logtext), imi->descriptor);
598 if ( (!(opcode == JAVA_INVOKEVIRTUAL)) &&
599 (! ( (imi->flags & ACC_STATIC )
600 || (imi->flags & ACC_PRIVATE)
601 || (imi->flags & ACC_FINAL ))) )
603 printf("DEBUG WARNING:PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n"); fflush(stdout);
605 log_text("PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n See method info after DEBUG WARNING\n");
610 tmp =inlining_analyse_method(imi, level + 1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack, inline_env);
611 list_addlast(newnode->inlinedmethods, tmp);
621 newnode->stopgp = gp;
622 label_index[jcodelength]=gp;
624 printf ("\nResult of inlining analysis of: ");
626 printf("was called by:\n"); fflush(stdout);
627 IMETHINFO(inline_env->method);
628 printf ("label_index[0..%d]->", jcodelength);
629 for (i=0;i<jcodelength; i++) printf ("%d:%d ", i, label_index[i]);
630 printf("stopgp : %d\n",newnode->stopgp);
636 /* --------------------------------------------------------------------*/
637 /* print_ functions: check inline structures contain what is expected */
638 /* --------------------------------------------------------------------*/
639 void print_t_inlining_globals (t_inlining_globals *g)
641 printf("\n------------\nt_inlining_globals struct for: \n\t");fflush(stdout);
642 METHINFOx(g->method);
643 printf("\tclass=");fflush(stdout);
644 utf_display(g->class->name);printf("\n");fflush(stdout);
646 printf("\tjcodelength=%i; jcode=%p;\n",g->jcodelength, g->jcode);
648 if (g->isinlinedmethod==true) {
649 printf("\tisinlinedmethod=true ");fflush(stdout);
652 printf("\tisinlinedmethod=false");fflush(stdout);
655 printf("\tcumjcodelength=%i ,cummaxstack=%i ,cumextablelength=%i ",
656 g->cumjcodelength, g->cummaxstack, g->cumextablelength);fflush(stdout);
657 printf("\tcumlocals=%i ,cummethods=%i \n",
658 g->cumlocals, g->cummethods);fflush(stdout);
660 printf("s>s>s> ");fflush(stdout);
661 print_inlining_stack (g->inlining_stack);
662 printf("i>i>i> "); fflush(stdout);
663 print_inlining_methodinfo(g->inlining_rootinfo);
664 printf("-------------------\n");fflush(stdout);
667 /* --------------------------------------------------------------------*/
668 void print_inlining_stack ( list *s)
671 printf("\n\tinlining_stack: NULL\n");
675 {/* print first element to see if get into stack */
676 t_inlining_stacknode *is;
677 printf("\n\tinlining_stack: NOT NULL\n");
681 printf("\n\tinlining_stack = init'd but EMPTY\n");
688 t_inlining_stacknode *is;
689 printf("\n\tinlining_stack: NOT NULL\n");
692 for (is=list_first(s);
694 is=list_next(s,is)) {
695 printf("\n\ti>--->inlining_stack entry: \n"); fflush(stdout);
696 METHINFOx(is->method);
697 printf("i=%i, p=%i, nextp=%i, opcode=%i;\n",
698 is->i,is->p,is->nextp,is->opcode);fflush(stdout);
699 print_inlining_methodinfo(is->inlinfo);
705 /* --------------------------------------------------------------------*/
706 void print_inlining_methodinfo( inlining_methodinfo *r) {
708 printf("\n\tinlining_methodinfo: NULL\n");
712 if (r->method != NULL) {
713 utf_display(r->method->class->name); printf("."); fflush(stdout); \
714 method_display(r->method); fflush(stdout); \
717 printf("method is NULL!!!!!\n");fflush(stdout);
720 printf("\n\tinlining_methodinfo for:"); fflush(stdout);
721 if (r->readonly==NULL) {
722 printf("\treadonly==NULL ");fflush(stdout);
726 printf("\treadonly=");fflush(stdout);
727 for (i = 0; i < r->method->maxlocals; i++) {
728 if (r->readonly[i] == true)
737 printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n",
738 r->startgp, r->stopgp, r->firstlocal, r->label_index);
740 printf ("label_index[0..%d]->", r->method->jcodelength);
741 for (i=0; i<r->method->jcodelength; i++) printf ("%d:%d ", i, r->label_index[i]);
745 inlining_methodinfo *im;
746 for (im=list_first(r->inlinedmethods);
748 im=list_next(r->inlinedmethods,im)) {
755 * These are local overrides for various environment variables in Emacs.
756 * Please do not remove this and leave it at the end of the file, where
757 * Emacs will automagically detect them.
758 * ---------------------------------------------------------------------
761 * indent-tabs-mode: t