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 1494 2004-11-12 13:34:26Z twisti $
42 #include "jit/inline.h"
44 #include "jit/parse.h"
45 #include "toolbox/logging.h"
46 #include "toolbox/memory.h"
49 utf_display(m->class->name); printf("."); fflush(stdout); \
50 method_display(m); fflush(stdout); \
52 #define IMETHINFO(m) \
53 utf_display(m->class->name); printf("."); fflush(stdout); \
54 method_display(m); fflush(stdout); \
55 printf("\tm->jcodelength=%i; ",m->jcodelength); fflush(stdout); \
56 printf("m->jcode=%p;\n",m->jcode); fflush(stdout); \
57 printf("\tm->maxlocals=%i; ",m->maxlocals); fflush(stdout); \
58 printf("m->maxstack=%i;\n",m->maxstack); fflush(stdout);
61 /* checked functions and macros: LOADCONST code_get OP1 BUILTIN block_insert bound_check ALIGN */
63 /* replace jcodelength loops with correct number after main for loop in parse()! */
66 /*-----------------------------------------------------------*/
67 /* just initialize global structure for non-inlining */
68 /*-----------------------------------------------------------*/
70 void inlining_init0(methodinfo *m, t_inlining_globals *inline_env)
72 /* initialization for normal use in parse */
73 inlining_set_compiler_variables_fun(m, inline_env);
74 inline_env->isinlinedmethod = 0;
75 inline_env->cumjcodelength = m->jcodelength; /* for not inlining */
77 inline_env->cummaxstack = m->maxstack; /*why has here been 0 ? */
78 inline_env->cumextablelength = 0;
79 inline_env->cumlocals = m->maxlocals;
80 inline_env->cummethods = 0; /* co not global or static-used only here? */
81 inline_env->inlining_stack = NULL;
82 inline_env->inlining_rootinfo = NULL;
86 /*-----------------------------------------------------------*/
88 void inlining_setup(methodinfo *m, t_inlining_globals *inline_env)
90 /* t_inlining_globals *inline_env = DNEW(t_inlining_globals); */
91 inlining_init0(m,inline_env);
93 /* define in options.h; Used in main.c, jit.c & inline.c */
95 if ((utf_new_char("main") == m->name) && (useinliningm))
102 printf("\n-------- Inlining init for: "); fflush(stdout);
105 inline_env->cumjcodelength = 0;
106 inline_env->inlining_stack = NEW(list);
107 list_init(inline_env->inlining_stack,
108 OFFSET(t_inlining_stacknode, linkage));
109 /*------ analyze ------*/
110 if (DEBUGi==true) {print_t_inlining_globals(inline_env);}
111 inline_env->inlining_rootinfo
112 = inlining_analyse_method(m, 0, 0, 0, 0, inline_env);
113 if (DEBUGi==true) {print_t_inlining_globals(inline_env);}
114 /*---------------------*/
116 if (inline_env->cummethods == 0) {
117 inline_env = DNEW(t_inlining_globals);
118 inlining_init0(m,inline_env);
123 printf("(l,s) (%i,%i) was (%i,%i)\n",
124 m->maxlocals, inline_env->cumlocals,
125 m->maxstack, inline_env->cummaxstack); fflush(stdout);
129 m->maxlocals = inline_env->cumlocals; //orig not used
130 m->maxstack = inline_env->cummaxstack; //orig global maxstack var!!
136 void inlining_cleanup(t_inlining_globals *inline_env)
138 FREE(inline_env->inlining_stack, t_inlining_stacknode);
142 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)
144 t_inlining_stacknode *new = NEW(t_inlining_stacknode);
149 new->opcode = opcode;
150 new->method = inline_env->method;
151 new->lineindex=lineindex;
152 new->currentline=currentline;
153 new->linepcchange=linepcchange;
154 new->inlinfo = inlinfo;
155 list_addfirst(inline_env->inlining_stack, new);
156 inline_env->isinlinedmethod++;
160 void inlining_pop_compiler_variables(
161 int *i, int *p, int *nextp,
162 int *opcode, u2 *lineindex,
163 u2 *currentline,u2 *linepcchange,
164 inlining_methodinfo **inlinfo,
165 t_inlining_globals *inline_env)
167 t_inlining_stacknode *tmp
168 = (t_inlining_stacknode *) list_first(inline_env->inlining_stack);
170 if (!inline_env->isinlinedmethod) panic("Attempting to pop from inlining stack in toplevel method!\n");
175 *opcode = tmp->opcode;
177 *lineindex=tmp->lineindex;
178 *currentline=tmp->currentline;
179 *currentline=tmp->linepcchange;
181 *inlinfo = tmp->inlinfo;
183 inline_env->method = tmp->method; /*co*/
184 inline_env->class = inline_env->method->class; /*co*/
185 inline_env->jcodelength = inline_env->method->jcodelength; /*co*/
186 inline_env->jcode = inline_env->method->jcode; /*co*/
188 list_remove(inline_env->inlining_stack, tmp);
189 FREE(tmp, t_inlining_stacknode);
190 inline_env->isinlinedmethod--;
194 void inlining_set_compiler_variables_fun(methodinfo *m,
195 t_inlining_globals *inline_env)
198 inline_env->method = m; /*co*/
199 inline_env->class = m->class; /*co*/
200 inline_env->jcode = m->jcode; /*co*/
201 inline_env->jcodelength = m->jcodelength; /*co*/
205 classinfo *first_occurence(classinfo* class, utf* name, utf* desc)
207 classinfo *first = class;
209 for (; class->super != NULL ; class = class->super) {
210 if (class_findmethod(class->super, name, desc) != NULL) {
211 first = class->super;
219 bool is_unique_rec(classinfo *class, methodinfo *m, utf* name, utf* desc)
221 methodinfo *tmp = class_findmethod(class, name, desc);
222 if ((tmp != NULL) && (tmp != m))
225 for (; class != NULL; class = class->nextsub) {
226 if ((class->sub != NULL) && !is_unique_rec(class->sub, m, name, desc)) {
234 bool is_unique_method(classinfo *class, methodinfo *m, utf* name, utf* desc)
236 classinfo *firstclass;
238 /* sprintf (logtext, "First occurence of: ");
239 utf_sprint (logtext+strlen(logtext), m->class->name);
240 strcpy (logtext+strlen(logtext), ".");
241 utf_sprint (logtext+strlen(logtext), m->name);
242 utf_sprint (logtext+strlen(logtext), m->descriptor);
245 firstclass = first_occurence(class, name, desc);
247 /* sprintf (logtext, "\nis in class:");
248 utf_sprint (logtext+strlen(logtext), firstclass->name);
251 if (firstclass != class) return false;
253 return is_unique_rec(class, m, name, desc);
256 /* is_unique_method2 - returns count of # methods used up to 2
257 since if 2 used then not unique.
258 Chose not to make an extra fn call so
259 can return boolean instead of cnt.
260 It looks for subclasses with method def'd.
262 This replaces is_unique_method which for
263 reasons unknown looks up the class heirarchy
264 not down at subclasses.
266 * class - where looking for method
267 * m - original method ptr
268 * name - utf name of method
269 * desc - utf method descriptor
271 int is_unique_method2(classinfo *class, methodinfo *m, utf* name, utf* desc)
273 int cnt = 0; /* number of times method found in USED classes in hierarchy*/
276 if ((m->class == class) && (class->classUsed == USED))
279 if ( ((m->flags & ACC_FINAL) &&
280 (m->monoPoly != POLY))
281 || (class->sub == NULL))
284 for (subs = class->sub;subs != NULL;subs = subs->nextsub) {
287 sm = class_resolveclassmethod(subs,name,desc,class,false);
289 cnt =+ is_unique_method2(subs,sm,name,desc);
298 methodinfo *get_unique_method2(classinfo *class, methodinfo *m, utf* name, utf* desc)
303 if ((m->class == class) && (class->classUsed == USED))
306 for (subs = class->sub;subs != NULL;subs = subs->nextsub) {
309 sm = class_resolveclassmethod(subs,name,desc,class,false);
311 imi = get_unique_method2(subs,sm,name,desc);
321 inlining_methodinfo *inlining_analyse_method(methodinfo *m,
323 int firstlocal, int maxstackdepth,
324 t_inlining_globals *inline_env)
326 inlining_methodinfo *newnode = DNEW(inlining_methodinfo);
327 /*u1 *jcode = m->jcode;*/
328 int jcodelength = m->jcodelength;
333 bool iswide = false, oldiswide;
334 bool *readonly = NULL;
335 int *label_index = NULL;
336 bool isnotrootlevel = (level > 0);
337 bool isnotleaflevel = (level < INLINING_MAXDEPTH);
339 /* if (level == 0) gp = 0; */
341 sprintf (logtext, "Performing inlining analysis of: ");
342 utf_sprint (logtext+strlen(logtext), m->class->name);
343 strcpy (logtext+strlen(logtext), ".");
344 utf_sprint (logtext+strlen(logtext), m->name);
345 utf_sprint (logtext+strlen(logtext), m->descriptor);
348 if (isnotrootlevel) {
349 newnode->readonly = readonly = DMNEW(bool, m->maxlocals); /* FIXME only paramcount entrys necessary */
350 for (i = 0; i < m->maxlocals; readonly[i++] = true);
351 isnotrootlevel = true;
357 label_index = DMNEW(int, jcodelength+200);
359 newnode->inlinedmethods = DNEW(list);
360 list_init(newnode->inlinedmethods, OFFSET(inlining_methodinfo, linkage));
363 newnode->startgp = gp;
364 newnode->readonly = readonly;
365 newnode->label_index = label_index;
366 newnode->firstlocal = firstlocal;
367 inline_env->cumjcodelength += jcodelength + m->paramcount + 1 + 5;
369 if ((firstlocal + m->maxlocals) > inline_env->cumlocals) {
370 inline_env->cumlocals = firstlocal + m->maxlocals;
373 if ((maxstackdepth + m->maxstack) > inline_env->cummaxstack) {
374 inline_env->cummaxstack = maxstackdepth + m->maxstack;
377 inline_env->cumextablelength += m->exceptiontablelength;
380 for (p = 0; p < jcodelength; gp += (nextp - p), p = nextp) {
381 opcode = code_get_u1 (p,m);
382 nextp = p + jcommandsize[opcode];
385 /* figure out nextp */
419 case JAVA_LOOKUPSWITCH:
420 nextp = ALIGN((p + 1), 4) + 4;
421 nextp += code_get_u4(nextp,m) * 8 + 4;
424 case JAVA_TABLESWITCH:
425 nextp = ALIGN((p + 1), 4) + 4;
426 nextp += (code_get_u4(nextp+4,m) - code_get_u4(nextp,m) + 1) * 4 + 4 +4;
430 /* detect readonly variables in inlined methods */
432 if (isnotrootlevel) {
433 bool iswide = oldiswide;
442 i = code_get_u1(p + 1,m);
445 i = code_get_u2(p + 1,m);
480 i = code_get_u1(p + 1,m);
483 i = code_get_u2(p + 1,m);
490 /* for (i=lastlabel; i<=p; i++) label_index[i] = gp;
491 // printf("lastlabel=%d p=%d gp=%d\n",lastlabel, p, gp);
493 for (i = p; i < nextp; i++) label_index[i] = gp;
495 if (isnotleaflevel) {
498 case JAVA_INVOKEVIRTUAL:
501 /*log_text("\nINLINE INVOKEVIRTUAL :\t");*/
502 case JAVA_INVOKESPECIAL:
503 case JAVA_INVOKESTATIC:
504 i = code_get_u2(p + 1,m);
506 constant_FMIref *imr;
510 bool uniqueVirt= false;
513 imr = class_getconstant(m->class, i, CONSTANT_Methodref);
515 if (!class_load(imr->class))
518 if (!class_link(imr->class))
521 imi = class_resolveclassmethod(imr->class,
528 panic("Exception thrown while parsing bytecode"); /* XXX should be passed on */
530 if ( (utf_new_char("<init>") == imi->name) ||
531 (utf_new_char("<clinit>") == imi->name)) break;
533 if (opcode == JAVA_INVOKEVIRTUAL) {
534 vcnt = is_unique_method2(imi->class, imi, imr->name, imr->descriptor);
537 imi1 = get_unique_method2(imi->class, imi, imr->name, imr->descriptor);
540 /*log_text("WAS unique virtual\t");*/
541 /**/ uniqueVirt=true; /* comment out to permanently turn off inlining virtuals*/
545 if (!is_unique_method(imi->class, imi, imr->name, imr->descriptor))
549 /*if (imi->flags & ACC_NATIVE) log_text("Native method,no inlining");*/
550 if ((inline_env->cummethods < INLINING_MAXMETHODS) &&
551 (!(imi->flags & ACC_NATIVE)) &&
552 (inlineoutsiders || (m->class == imr->class)) &&
553 (imi->jcodelength < INLINING_MAXCODESIZE) &&
554 (imi->jcodelength > 0) &&
555 (((!inlinevirtuals) || (uniqueVirt)) || (opcode != JAVA_INVOKEVIRTUAL)) &&
556 (inlineexceptions || (imi->exceptiontablelength == 0))) { /* FIXME: eliminate empty methods? */
557 inlining_methodinfo *tmp;
558 descriptor2types(imi);
560 inline_env->cummethods++;
563 char logtext[MAXLOGTEXT];
564 sprintf(logtext, "Going to inline: ");
565 utf_sprint(logtext +strlen(logtext), imi->class->name);
566 strcpy(logtext + strlen(logtext), ".");
567 utf_sprint(logtext + strlen(logtext), imi->name);
568 utf_sprint(logtext + strlen(logtext), imi->descriptor);
571 if ( (!(opcode == JAVA_INVOKEVIRTUAL)) &&
572 (! ( (imi->flags & ACC_STATIC )
573 || (imi->flags & ACC_PRIVATE)
574 || (imi->flags & ACC_FINAL ))) )
576 printf("DEBUG WARNING:PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n"); fflush(stdout);
578 log_text("PROBABLE INLINE PROBLEM flags not static, private or final for non-virtual inlined method\n See method info after DEBUG WARNING\n");
583 tmp =inlining_analyse_method(imi, level + 1, gp, firstlocal + m->maxlocals, maxstackdepth + m->maxstack, inline_env);
584 list_addlast(newnode->inlinedmethods, tmp);
594 newnode->stopgp = gp;
597 printf ("\nResult of inlining analysis of: ");
599 printf("was called by:\n"); fflush(stdout);
600 IMETHINFO(inline_env->method);
601 printf ("label_index[0..%d]->", jcodelength);
602 for (i=0;i<jcodelength; i++) printf ("%d:%d ", i, label_index[i]);
603 printf("stopgp : %d\n",newnode->stopgp);
609 /* --------------------------------------------------------------------*/
610 /* print_ functions: check inline structures contain what is expected */
611 /* --------------------------------------------------------------------*/
612 void print_t_inlining_globals (t_inlining_globals *g)
614 printf("\n------------\nt_inlining_globals struct for: \n\t");fflush(stdout);
616 printf("\tclass=");fflush(stdout);
617 utf_display(g->class->name);printf("\n");fflush(stdout);
619 printf("\tjcodelength=%i; jcode=%p;\n",g->jcodelength, g->jcode);
621 if (g->isinlinedmethod==true) {
622 printf("\tisinlinedmethod=true ");fflush(stdout);
625 printf("\tisinlinedmethod=false");fflush(stdout);
628 printf("\tcumjcodelength=%i ,cummaxstack=%i ,cumextablelength=%i ",
629 g->cumjcodelength, g->cummaxstack, g->cumextablelength);fflush(stdout);
630 printf("\tcumlocals=%i ,cummethods=%i \n",
631 g->cumlocals, g->cummethods);fflush(stdout);
633 printf("s>s>s> ");fflush(stdout);
634 print_inlining_stack (g->inlining_stack);
635 printf("i>i>i> "); fflush(stdout);
636 print_inlining_methodinfo(g->inlining_rootinfo);
637 printf("-------------------\n");fflush(stdout);
640 /* --------------------------------------------------------------------*/
641 void print_inlining_stack ( list *s)
644 printf("\n\tinlining_stack: NULL\n");
648 {/* print first element to see if get into stack */
649 t_inlining_stacknode *is;
650 printf("\n\tinlining_stack: NOT NULL\n");
654 printf("\n\tinlining_stack = init'd but EMPTY\n");
661 t_inlining_stacknode *is;
662 printf("\n\tinlining_stack: NOT NULL\n");
665 for (is=list_first(s);
667 is=list_next(s,is)) {
668 printf("\n\ti>--->inlining_stack entry: \n"); fflush(stdout);
669 METHINFO(is->method);
670 printf("i=%i, p=%i, nextp=%i, opcode=%i;\n",
671 is->i,is->p,is->nextp,is->opcode);fflush(stdout);
672 print_inlining_methodinfo(is->inlinfo);
678 /* --------------------------------------------------------------------*/
679 void print_inlining_methodinfo( inlining_methodinfo *r) {
681 printf("\n\tinlining_methodinfo: NULL\n");
685 if (r->method != NULL) {
686 utf_display(r->method->class->name); printf("."); fflush(stdout); \
687 method_display(r->method); fflush(stdout); \
690 printf("method is NULL!!!!!\n");fflush(stdout);
693 printf("\n\tinlining_methodinfo for:"); fflush(stdout);
694 if (r->readonly==NULL) {
695 printf("\treadonly==NULL ");fflush(stdout);
699 printf("\treadonly=");fflush(stdout);
700 for (i = 0; i < r->method->maxlocals; i++) {
701 if (r->readonly[i] == true)
710 printf("\tstartgp=%i; stopgp=%i; firstlocal=%i; label_index=%p;\n",
711 r->startgp, r->stopgp, r->firstlocal, r->label_index);
713 printf ("label_index[0..%d]->", r->method->jcodelength);
714 for (i=0; i<r->method->jcodelength; i++) printf ("%d:%d ", i, r->label_index[i]);
718 inlining_methodinfo *im;
719 for (im=list_first(r->inlinedmethods);
721 im=list_next(r->inlinedmethods,im)) {
728 * These are local overrides for various environment variables in Emacs.
729 * Please do not remove this and leave it at the end of the file, where
730 * Emacs will automagically detect them.
731 * ---------------------------------------------------------------------
734 * indent-tabs-mode: t